mirror of
https://github.com/cliffe/SecGen.git
synced 2026-02-21 11:18:06 +00:00
Merge branch 'master' of https://github.com/emlynbutterfield/SecGen
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -16,4 +16,4 @@ modules/encoders/compression/huffman/tmp
|
||||
.rakeTasks
|
||||
modules/**/Gemfile.lock
|
||||
modules/generators/network/pcap/files/packet.pcap
|
||||
lib/resources/images/scenario
|
||||
lib/resources/images/scenario
|
||||
|
||||
2
Gemfile
2
Gemfile
@@ -34,6 +34,8 @@ gem 'rsa'
|
||||
gem 'gpgmeh'
|
||||
gem 'digest-sha3', :git => "http://github.com/izetex/digest-sha3-ruby"
|
||||
gem 'packetfu'
|
||||
gem 'net-ntp'
|
||||
gem 'CFPropertyList'
|
||||
|
||||
#development only gems go here
|
||||
group :test, :development do
|
||||
|
||||
58
Gemfile.lock
58
Gemfile.lock
@@ -19,17 +19,18 @@ GIT
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
CFPropertyList (2.3.6)
|
||||
PriorityQueue (0.1.2)
|
||||
activesupport (5.2.1)
|
||||
activesupport (5.2.3)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 0.7, < 2)
|
||||
minitest (~> 5.1)
|
||||
tzinfo (~> 1.1)
|
||||
bases (1.0.2)
|
||||
bcrypt (3.1.12)
|
||||
chunky_png (1.3.10)
|
||||
bcrypt (3.1.13)
|
||||
chunky_png (1.3.11)
|
||||
cinch (2.3.4)
|
||||
concurrent-ruby (1.0.5)
|
||||
concurrent-ruby (1.1.5)
|
||||
credy (0.2.1)
|
||||
thor (~> 0.19.1)
|
||||
digest-simple (1.1.0)
|
||||
@@ -38,14 +39,15 @@ GEM
|
||||
digest-whirlpool (1.0.3)
|
||||
duplicate (1.1.1)
|
||||
facter (2.5.1)
|
||||
faker (1.9.1)
|
||||
CFPropertyList (~> 2.2)
|
||||
faker (1.9.3)
|
||||
i18n (>= 0.7)
|
||||
faraday (0.13.1)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
faraday_middleware (0.12.2)
|
||||
faraday (>= 0.7.4, < 1.0)
|
||||
fast_gettext (1.1.2)
|
||||
ffi (1.9.25)
|
||||
ffi (1.11.1)
|
||||
ffi-compiler (1.0.1)
|
||||
ffi (>= 1.0.0)
|
||||
rake
|
||||
@@ -60,16 +62,16 @@ GEM
|
||||
gpgmeh (0.1.6)
|
||||
activesupport (>= 2.3)
|
||||
nio4r (~> 2.2)
|
||||
hiera (3.4.5)
|
||||
hiera (3.5.0)
|
||||
hocon (1.2.5)
|
||||
httpclient (2.8.3)
|
||||
huffman (0.0.1)
|
||||
PriorityQueue
|
||||
activesupport
|
||||
ruby-graphviz
|
||||
i18n (1.1.0)
|
||||
i18n (1.6.0)
|
||||
concurrent-ruby (~> 1.0)
|
||||
json (2.1.0)
|
||||
json (2.2.0)
|
||||
librarian-puppet (3.0.0)
|
||||
librarianp (>= 0.6.3)
|
||||
puppet_forge (~> 2.1)
|
||||
@@ -80,23 +82,25 @@ GEM
|
||||
mini_exiftool (2.9.0)
|
||||
mini_exiftool_vendored (9.2.7.v1)
|
||||
mini_exiftool (>= 1.6.0)
|
||||
mini_portile2 (2.3.0)
|
||||
minitar (0.6.1)
|
||||
mini_portile2 (2.4.0)
|
||||
minitar (0.8)
|
||||
minitest (5.11.3)
|
||||
multi_json (1.13.1)
|
||||
multipart-post (2.0.0)
|
||||
multipart-post (2.1.1)
|
||||
net-ntp (2.1.3)
|
||||
nio4r (2.3.1)
|
||||
nokogiri (1.8.4)
|
||||
mini_portile2 (~> 2.3.0)
|
||||
nokogiri (1.10.3)
|
||||
mini_portile2 (~> 2.4.0)
|
||||
nori (2.6.0)
|
||||
ovirt-engine-sdk (4.2.4)
|
||||
ovirt-engine-sdk (4.3.0)
|
||||
json (>= 1, < 3)
|
||||
packetfu (1.1.13)
|
||||
pcaprub
|
||||
pcaprub (0.13.0)
|
||||
pg (1.1.3)
|
||||
pg (1.1.4)
|
||||
process_helper (0.1.2)
|
||||
puppet (6.0.0)
|
||||
puppet (6.4.2)
|
||||
CFPropertyList (~> 2.2)
|
||||
facter (> 2.0.1, < 4)
|
||||
fast_gettext (~> 1.1.2)
|
||||
hiera (>= 3.2.1, < 4)
|
||||
@@ -105,7 +109,7 @@ GEM
|
||||
multi_json (~> 1.10)
|
||||
puppet-resource_api (~> 1.5)
|
||||
semantic_puppet (~> 1.0)
|
||||
puppet-resource_api (1.5.0)
|
||||
puppet-resource_api (1.8.3)
|
||||
hocon (>= 1.0)
|
||||
puppet_forge (2.2.9)
|
||||
faraday (>= 0.9.0, < 0.14.0)
|
||||
@@ -113,23 +117,23 @@ GEM
|
||||
gettext-setup (~> 0.11)
|
||||
minitar
|
||||
semantic_puppet (~> 1.0)
|
||||
rake (12.3.1)
|
||||
rdoc (6.0.4)
|
||||
rake (12.3.2)
|
||||
rdoc (6.1.1)
|
||||
redcarpet (3.4.0)
|
||||
rmagick (2.16.0)
|
||||
rmagick (3.2.0)
|
||||
rqrcode (0.10.1)
|
||||
chunky_png (~> 1.0)
|
||||
rsa (0.1.4)
|
||||
rsync (1.0.9)
|
||||
ruby-graphviz (1.2.3)
|
||||
rubyzip (1.2.2)
|
||||
ruby-graphviz (1.2.4)
|
||||
rubyzip (1.2.3)
|
||||
scrypt (3.0.6)
|
||||
ffi-compiler (>= 1.0, < 2.0)
|
||||
semantic_puppet (1.0.2)
|
||||
smbhash (1.0.2)
|
||||
spidr (0.6.0)
|
||||
nokogiri (~> 1.3)
|
||||
sshkey (1.9.0)
|
||||
sshkey (2.0.0)
|
||||
text (1.3.1)
|
||||
thor (0.19.4)
|
||||
thread_safe (0.3.6)
|
||||
@@ -137,7 +141,7 @@ GEM
|
||||
thread_safe (~> 0.1)
|
||||
wordlist (0.1.1)
|
||||
spidr (~> 0.2)
|
||||
yard (0.9.16)
|
||||
yard (0.9.19)
|
||||
zip-zip (0.3)
|
||||
rubyzip (>= 1.0.0)
|
||||
zipruby (0.3.6)
|
||||
@@ -146,6 +150,7 @@ PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
CFPropertyList
|
||||
bases
|
||||
bcrypt
|
||||
braille!
|
||||
@@ -162,6 +167,7 @@ DEPENDENCIES
|
||||
librarian-puppet
|
||||
mini_exiftool_vendored
|
||||
minitest
|
||||
net-ntp
|
||||
nokogiri
|
||||
nori
|
||||
ovirt-engine-sdk
|
||||
@@ -186,4 +192,4 @@ DEPENDENCIES
|
||||
zipruby
|
||||
|
||||
BUNDLED WITH
|
||||
2.0.1
|
||||
1.11.2
|
||||
|
||||
@@ -238,7 +238,7 @@ We encourage contributions to the project.
|
||||
Briefly, please fork from http://github.com/cliffe/SecGen/, create a branch, make and commit your changes, then create a pull request.
|
||||
|
||||
## Resources
|
||||
Paper: [Z.C. Schreuders, T. Shaw, A. Mac Muireadhaigh, and P. Staniforth, “Hackerbot: Attacker Chatbots for Randomised and Interactive Security Labs, Using SecGen and oVirt,” USENIX Workshop on Advances in Security Education (ASE'18), Baltimore, MD, USA. USENIX Association, 2017.](https://www.usenix.org/conference/ase18/presentation/schreuders) (This paper describes Hackerbot and how we use SecGen with oVirt.)
|
||||
Paper: [Z.C. Schreuders, T. Shaw, A. Mac Muireadhaigh, and P. Staniforth, “Hackerbot: Attacker Chatbots for Randomised and Interactive Security Labs, Using SecGen and oVirt,” USENIX Workshop on Advances in Security Education (ASE'18), Baltimore, MD, USA. USENIX Association, 2018.](https://www.usenix.org/conference/ase18/presentation/schreuders) (This paper describes Hackerbot and how we use SecGen with oVirt.)
|
||||
|
||||
Paper: [Z.C. Schreuders, T. Shaw, M. Shan-A-Khuda, G. Ravichandran, J. Keighley, and M. Ordean, “Security Scenario Generator (SecGen): A Framework for Generating Randomly Vulnerable Rich-scenario VMs for Learning Computer Security and Hosting CTF Events,” USENIX Workshop on Advances in Security Education (ASE'17), Vancouver, BC, Canada. USENIX Association, 2017.](https://www.usenix.org/conference/ase17/workshop-program/presentation/schreuders) (This paper provides a good overview of SecGen.)
|
||||
|
||||
|
||||
@@ -4,13 +4,13 @@ After=postgresql.service
|
||||
|
||||
[Service]
|
||||
EnvironmentFile=/etc/environment
|
||||
ExecStart=/usr/bin/ruby /home/secgen/SecGen/lib/batch/batch_secgen.rb start
|
||||
ExecStart=/usr/bin/ruby /home/deploy/SecGen/lib/batch/batch_secgen.rb start
|
||||
ExecReload=/bin/kill -HUP $MAINPID
|
||||
KillMode=process
|
||||
WorkingDirectory=/home/secgen/SecGen/
|
||||
WorkingDirectory=/home/deploy/SecGen/
|
||||
Restart=always
|
||||
User=secgen
|
||||
Group=secgen
|
||||
User=deploy
|
||||
Group=deploy
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
@@ -304,8 +304,8 @@ end
|
||||
# Database interactions
|
||||
def insert_row(db_conn, prepared_statements, statement_id, secgen_args)
|
||||
statement = "insert_row_#{statement_id}"
|
||||
# Add --shutdown and strip trailing whitespace
|
||||
secgen_args = '--shutdown ' + secgen_args.strip
|
||||
# Add --shutdown and --no-tests and strip trailing whitespace
|
||||
secgen_args = '--shutdown --no-tests ' + secgen_args.strip
|
||||
Print.info "Adding to queue: '#{statement}' '#{secgen_args}' 'todo'"
|
||||
unless prepared_statements.include? statement
|
||||
db_conn.prepare(statement, 'insert into queue (secgen_args, status) values ($1, $2) returning id')
|
||||
|
||||
@@ -58,33 +58,36 @@ class HackerbotConfigGenerator < StringGenerator
|
||||
begin
|
||||
doc = Nokogiri::XML(xml_config)
|
||||
rescue
|
||||
Print.err "Failed to process hackerbot config"
|
||||
exit
|
||||
abort "Failed to process hackerbot config"
|
||||
end
|
||||
# remove xml namespaces for ease of processing
|
||||
doc.remove_namespaces!
|
||||
# for each element in the vulnerability
|
||||
hackerbot = doc.xpath("/hackerbot")
|
||||
name = hackerbot.xpath("name").first.content
|
||||
lab_sheet += hackerbot.xpath("tutorial_info/tutorial").first.content + "\n"
|
||||
begin
|
||||
# remove xml namespaces for ease of processing
|
||||
doc.remove_namespaces!
|
||||
# for each element in the vulnerability
|
||||
hackerbot = doc.xpath("/hackerbot")
|
||||
name = hackerbot.xpath("name").first.content
|
||||
lab_sheet += hackerbot.xpath("tutorial_info/tutorial").first.content + "\n"
|
||||
|
||||
doc.xpath("//attack").each_with_index do |attack, index|
|
||||
attack.xpath("tutorial").each do |tutorial_snippet|
|
||||
lab_sheet += tutorial_snippet.content + "\n"
|
||||
end
|
||||
doc.xpath("//attack").each_with_index do |attack, index|
|
||||
attack.xpath("tutorial").each do |tutorial_snippet|
|
||||
lab_sheet += tutorial_snippet.content + "\n"
|
||||
end
|
||||
|
||||
lab_sheet += "#### #{name} Attack ##{index + 1}\n"
|
||||
lab_sheet += "Use what you have learned to complete the bot's challenge. You can skip the bot to here, by saying '**goto #{index + 1}**'\n\n"
|
||||
lab_sheet += "> #{name}: \"#{attack.xpath('prompt').first.content}\" \n\n"
|
||||
lab_sheet += "Do any necessary preparation, then when you are ready for the bot to complete the action/attack, ==say 'ready'==\n\n"
|
||||
if attack.xpath("quiz").size > 0
|
||||
lab_sheet += "There is a quiz to complete. Once Hackerbot asks you the question you can =='answer *YOURANSWER*'==\n\n"
|
||||
lab_sheet += "#### #{name} Attack ##{index + 1}\n"
|
||||
lab_sheet += "Use what you have learned to complete the bot's challenge. You can skip the bot to here, by saying '**goto #{index + 1}**'\n\n"
|
||||
lab_sheet += "> #{name}: \"#{attack.xpath('prompt').first.content}\" \n\n"
|
||||
lab_sheet += "Do any necessary preparation, then when you are ready for the bot to complete the action/attack, ==say 'ready'==\n\n"
|
||||
if attack.xpath("quiz").size > 0
|
||||
lab_sheet += "There is a quiz to complete. Once Hackerbot asks you the question you can =='answer *YOURANSWER*'==\n\n"
|
||||
end
|
||||
lab_sheet += "Don't forget to ==save and submit any flags!==\n\n"
|
||||
end
|
||||
lab_sheet += "Don't forget to ==save and submit any flags!==\n\n"
|
||||
lab_sheet += hackerbot.xpath("tutorial_info/footer").first.content + "\n"
|
||||
|
||||
lab_sheet
|
||||
rescue Exception => e
|
||||
abort "Failed to generate lab sheet: #{e.message}\n#{e.backtrace}"
|
||||
end
|
||||
lab_sheet += hackerbot.xpath("tutorial_info/footer").first.content + "\n"
|
||||
|
||||
lab_sheet
|
||||
end
|
||||
|
||||
def generate
|
||||
|
||||
170
lib/objects/post_provision_test.rb
Normal file
170
lib/objects/post_provision_test.rb
Normal file
@@ -0,0 +1,170 @@
|
||||
# Post Provision Testing
|
||||
#
|
||||
# This file will be copied into each project folder at creation time.
|
||||
# It will be required from each of the modules/secgen_tests/module_name.rb test scripts
|
||||
#
|
||||
# Test classes must: require_relative '../../../../../lib/post_provision_test'
|
||||
|
||||
require 'json'
|
||||
require 'base64'
|
||||
require 'socket'
|
||||
require 'timeout'
|
||||
require 'net/http'
|
||||
require 'open3'
|
||||
|
||||
class PostProvisionTest
|
||||
attr_accessor :project_path
|
||||
attr_accessor :system_ip
|
||||
attr_accessor :module_name
|
||||
attr_accessor :module_path
|
||||
attr_accessor :json_inputs
|
||||
attr_accessor :port
|
||||
attr_accessor :outputs
|
||||
attr_accessor :all_tests_passed
|
||||
|
||||
def initialize
|
||||
self.outputs = []
|
||||
self.system_ip = get_system_ip
|
||||
self.json_inputs = get_json_inputs
|
||||
self.port = get_port
|
||||
self.all_tests_passed = true
|
||||
end
|
||||
|
||||
def run
|
||||
test_module
|
||||
puts self.outputs
|
||||
exit(1) unless all_tests_passed
|
||||
end
|
||||
|
||||
def test_module
|
||||
# Call super first in overriden methods
|
||||
self.outputs << "Running tests for #{self.module_name}"
|
||||
end
|
||||
|
||||
#####################
|
||||
# Testing Functions #
|
||||
#####################
|
||||
|
||||
# Test service is up (tcp)
|
||||
def test_service_up
|
||||
if is_port_open? system_ip, self.port
|
||||
self.outputs << "PASSED: Port #{self.port} is open at #{get_system_ip} (#{get_system_name})!"
|
||||
else
|
||||
self.outputs << "FAILED: Port #{self.port} is closed at #{get_system_ip} (#{get_system_name})!"
|
||||
self.all_tests_passed = false
|
||||
end
|
||||
end
|
||||
|
||||
# example usage for page: /index.html
|
||||
def test_html_returned_content(page, match_string, hide_content = false)
|
||||
|
||||
begin
|
||||
source = Net::HTTP.get(get_system_ip, page, self.port)
|
||||
rescue SocketError, Errno::ECONNREFUSED
|
||||
# do nothing
|
||||
end
|
||||
|
||||
if source and source.include? match_string
|
||||
match_string = '<redacted>' if hide_content
|
||||
self.outputs << "PASSED: Content #{match_string} is contained within #{page} at #{get_system_ip}:#{self.port} (#{get_system_name})!"
|
||||
else
|
||||
self.outputs << "FAILED: Content #{match_string} is not contained within #{page} at #{get_system_ip}:#{self.port} (#{get_system_name})!"
|
||||
self.all_tests_passed = false
|
||||
end
|
||||
end
|
||||
|
||||
def test_local_command(test_output, local_command, match_string)
|
||||
Dir.chdir(get_project_path) do
|
||||
output = run_vagrant_ssh(local_command)
|
||||
if output[:stdout].include? match_string or output[:stderr].include? match_string
|
||||
self.outputs << "PASSED: #{test_output} local command (#{local_command}) matches with output (#{match_string}) on #{get_system_name}!"
|
||||
else
|
||||
self.outputs << "FAILED: #{test_output} local command (#{local_command}) matches with output (#{match_string}) on #{get_system_name}!"
|
||||
self.outputs << output[:stderr]
|
||||
self.all_tests_passed = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
##################
|
||||
# Misc Functions #
|
||||
##################
|
||||
|
||||
def run_vagrant_ssh(args)
|
||||
stdout, stderr, status = Open3.capture3("/usr/bin/vagrant ssh #{get_system_name} -c '#{args}'")
|
||||
{:stdout => stdout, :stderr => stderr, :exit_status => status}
|
||||
end
|
||||
|
||||
def get_system_ip
|
||||
vagrant_file_path = "#{get_project_path}/Vagrantfile"
|
||||
vagrantfile = File.read(vagrant_file_path)
|
||||
ip_line = vagrantfile.split("\n").delete_if {|line| !line.include? "# ip_address_for_#{get_system_name}"}[0]
|
||||
ip_address = ip_line.split('=')[-1]
|
||||
if ip_address == "DHCP"
|
||||
puts "WARNING: Cannot test against dynamic IPs" # TODO: fix this so that we grab dynamic IP address (maybe from vagrant?)
|
||||
exit(0) # return "OK", if we can't test
|
||||
else
|
||||
ip_address
|
||||
end
|
||||
end
|
||||
|
||||
def get_json_inputs
|
||||
json_inputs_path = "#{File.expand_path('../', self.module_path)}/secgen_functions/files/json_inputs/*"
|
||||
json_inputs_files = Dir.glob(json_inputs_path)
|
||||
json_inputs_files.delete_if {|path| !path.include?(self.module_name)}
|
||||
if json_inputs_files.size > 0
|
||||
return JSON.parse(Base64.strict_decode64(File.read(json_inputs_files.first)))
|
||||
end
|
||||
{}
|
||||
end
|
||||
|
||||
def get_port
|
||||
if get_json_inputs != {} and get_json_inputs['port'] != nil
|
||||
get_json_inputs['port'][0].to_i
|
||||
else
|
||||
-1
|
||||
end
|
||||
end
|
||||
|
||||
# Pass __FILE__ in from subclasses
|
||||
def get_module_path(file_path)
|
||||
"#{File.expand_path('..', File.dirname(file_path))}"
|
||||
end
|
||||
|
||||
# Note: returns proftpd_testing
|
||||
def get_system_name
|
||||
get_system_path.match(/.*?([^\/]*)$/i).captures[0]
|
||||
end
|
||||
|
||||
# Note: returns /home/thomashaw/git/SecGen/projects/SecGen20190202_010552/puppet/proftpd_testing
|
||||
def get_system_path
|
||||
"#{File.expand_path('../../', self.module_path)}"
|
||||
end
|
||||
|
||||
# Note: returns /home/thomashaw/git/SecGen/projects/SecGen20190202_010552/
|
||||
def get_project_path
|
||||
"#{File.expand_path('../../../../', self.module_path)}"
|
||||
end
|
||||
|
||||
def is_port_open?(ip, port)
|
||||
retries = 5
|
||||
while retries > 0
|
||||
begin
|
||||
Timeout::timeout(2) do
|
||||
begin
|
||||
s = TCPSocket.new(ip, port)
|
||||
s.close
|
||||
return true
|
||||
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
|
||||
# do nothing
|
||||
end
|
||||
end
|
||||
rescue Timeout::Error
|
||||
# ignored
|
||||
end
|
||||
retries -= 1
|
||||
end
|
||||
false
|
||||
end
|
||||
|
||||
end
|
||||
@@ -178,6 +178,10 @@ class ProjectFilesCreator
|
||||
abort
|
||||
end
|
||||
|
||||
# Copy the test superclass into the project/lib directory
|
||||
Print.std "Copying post-provision testing class"
|
||||
FileUtils.mkdir("#{@out_dir}/lib")
|
||||
FileUtils.cp("#{ROOT_DIR}/lib/objects/post_provision_test.rb", "#{@out_dir}/lib/post_provision_test.rb")
|
||||
|
||||
Print.std "VM(s) can be built using 'vagrant up' in #{@out_dir}"
|
||||
|
||||
|
||||
2
lib/resources/linelists/README-sources.md
Normal file
2
lib/resources/linelists/README-sources.md
Normal file
@@ -0,0 +1,2 @@
|
||||
secrets: \#MyWeirdSecret on twitter
|
||||
https://twitter.com/hashtag/MYWEIRDSECRET?src=hash
|
||||
23
lib/resources/linelists/secrets
Normal file
23
lib/resources/linelists/secrets
Normal file
@@ -0,0 +1,23 @@
|
||||
I talk to my car when it needs gas by saying "don't worry mummy's gonna feed you now"
|
||||
I have a pair of wireless earphones. Sometimes when I don't want to talk, I put my headphones on and act like I can't hear.
|
||||
I count the hours of sleep I'm going to get before I go to sleep.
|
||||
I use and shift my plates around in my cupboard so the bottom ones don't feel left out.
|
||||
I keep a headband in my pocket just in case I get challenged to a dance battle.
|
||||
When I was little I used to lick our cat because I thought she missed her cat family.
|
||||
The only way I eat M&M's is by separating them by color and eating them from my least favorite color to my favorite.
|
||||
I buy surgical gloves only for binge-eating potato chips.
|
||||
I brush my my toes with a toothbrush with body wash on it in the shower.
|
||||
I often look at houses and buildings and rate if they are good bunkers for a zombie apocalypse.
|
||||
Whenever I eat Doritos I check to see which side has more 'flavor' and that's the side that gets to meet my tongue.
|
||||
When somebody cuts me off when I'm telling a story, I turn to the wall and finish telling it so I feel accomplished.
|
||||
I usually consult my dog before making any huge life decisions by asking her to blink for "yes" or not blink for "no".
|
||||
When people on tv wave, I always wave back to them, even though I know they can't see me.
|
||||
I always thank Siri after she performs a task so she'll befriend me if the robot apocalypse ever happens.
|
||||
People think I am rocking out to tunes & dancing in my car. I am really just animating old arguments I won & celebrating.
|
||||
When I mix my dogs wet and dry food together, I taste it to make sure it's okay.
|
||||
When I add paper to my printer, I have to move any paper left in the printer to the top to give them a chance to get used.
|
||||
I always carry two pennies with me so if someone asks me for my two cents, I'll be ready.
|
||||
I have my earphones on with no music so I can listen to other people's conversations.
|
||||
I like to make unexpected turns when driving just so I can hear the soothing voice of my GPS say "recalculating".
|
||||
Sometimes when I'm cooking I talk out loud to a fake camera and pretend that I have my own cooking show.
|
||||
When I don't like someone, I make an avatar of them on the Sims and make them live a hard life.
|
||||
@@ -166,20 +166,26 @@ end
|
||||
<% else %>
|
||||
<%= system.name %>.vm.network :<%= selected_module.attributes['type'].first %>, type: "dhcp", auto_config: false
|
||||
<% end %>
|
||||
<% # Below string is used within testing, do not delete. -%>
|
||||
# ip_address_for_<%= system.name %>=DHCP
|
||||
<% # Static networking -%>
|
||||
<% else -%>
|
||||
<% # Static oVirt networking -%>
|
||||
<% if (@options.has_key? :ovirtuser) && (@options.has_key? :ovirtpass) -%>
|
||||
<% interface = 'ens3' -%>
|
||||
<% if @ovirt_base_template and @ovirt_base_template =~ /kali|debian_desktop_kde/ -%>
|
||||
<% if @ovirt_base_template and @ovirt_base_template =~ /kali|debian_desktop_kde|debian_server/ -%>
|
||||
<% interface = 'eth0' -%>
|
||||
<% end -%>
|
||||
# use some shell scripting to identify the name of the network interface (eth0/ens3/...), and set the IP address statically
|
||||
<%= system.name %>.vm.provision 'shell', inline: "echo -e \"auto lo\niface lo inet loopback\n\nauto <%= interface %>\niface <%= interface %> inet static\n\taddress <%= resolve_network(selected_module)%>\" > /etc/network/interfaces"
|
||||
<%= system.name %>.vm.provision 'shell', inline: "echo '' > /etc/environment"
|
||||
<% # Static Virtualbox networking -%>
|
||||
<% # Below string is used within testing, do not delete. -%>
|
||||
# ip_address_for_<%= system.name %>=<%= resolve_network(selected_module)%>
|
||||
<% # Static Virtualbox networking -%>
|
||||
<% else -%>
|
||||
<%= system.name %>.vm.network :<%= selected_module.attributes['type'].first %>, ip: "<%= resolve_network(selected_module)%>"
|
||||
<% # Below string is used within testing, do not delete. -%>
|
||||
# ip_address_for_<%= system.name %>=<%= resolve_network(selected_module)%>
|
||||
<% end -%>
|
||||
<% end -%>
|
||||
<% when 'vulnerability', 'service', 'utility', 'build' -%>
|
||||
@@ -191,14 +197,14 @@ end
|
||||
b64_json_inputs = Base64.strict_encode64(json_inputs)
|
||||
# save the inputs in a randomly named file in the
|
||||
# project out directory of the secgen_functions module
|
||||
rand = SecureRandom.hex().to_s
|
||||
json_inputs_filename = "#{selected_module.module_path_end}_#{SecureRandom.hex(15).to_s}"
|
||||
dir = "#{@out_dir}/puppet/#{system.name}/modules/secgen_functions/files/json_inputs"
|
||||
FileUtils.mkdir_p(dir) unless File.exists?(dir)
|
||||
Print.verbose "Writing #{selected_module.module_path_name} input to: #{dir}/#{rand}"
|
||||
File.write("#{dir}/#{rand}", b64_json_inputs)
|
||||
Print.verbose "Writing #{selected_module.module_path_name} input to: #{dir}/#{json_inputs_filename}"
|
||||
File.write("#{dir}/#{json_inputs_filename}", b64_json_inputs)
|
||||
-%>
|
||||
<%= module_name%>.facter = {
|
||||
"base64_inputs_file" => '<%= rand %>',
|
||||
"base64_inputs_file" => '<%= json_inputs_filename %>',
|
||||
}
|
||||
<% end -%>
|
||||
<%=module_name%>.module_path = "<%="puppet/#{system.name}/modules"%>"
|
||||
|
||||
@@ -21,4 +21,5 @@
|
||||
|
||||
<reference>https://atlas.hashicorp.com/puppetlabs</reference>
|
||||
<software_license>various</software_license>
|
||||
|
||||
</base>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<distro>Debian 9.5.0 Stretch amd64</distro>
|
||||
<url>https://app.vagrantup.com/secgen/boxes/debian_stretch_desktop_kde/versions/1.2/providers/virtualbox.box</url>
|
||||
<esxi_url>https://app.vagrantup.com/redwiz666/boxes/debian_stretch_desktop_kde/versions/1.0.0/providers/vmware.box</esxi_url>
|
||||
<ovirt_template>stretch_desktop_kde_301118</ovirt_template>
|
||||
<ovirt_template>stretch_desktop_kde_140319</ovirt_template>
|
||||
|
||||
<reference>https://atlas.hashicorp.com/puppetlabs</reference>
|
||||
<software_license>various</software_license>
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<base xmlns="http://www.github/cliffe/SecGen/base"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.github/cliffe/SecGen/base">
|
||||
<name>Ubuntu Xenial 16.04 LTS 64-bit Server by puppetlabs</name>
|
||||
<author>Thomas Shaw</author>
|
||||
<module_license>GPLv3</module_license>
|
||||
<description>TODO </description>
|
||||
<cpu_word_size>64-bit</cpu_word_size>
|
||||
<type>server</type>
|
||||
<type>cli</type>
|
||||
|
||||
<platform>linux</platform>
|
||||
<platform>unix</platform>
|
||||
<distro>Ubuntu Xenial 16.04 LTS</distro>
|
||||
<url>https://app.vagrantup.com/puppetlabs/boxes/ubuntu-16.04-64-puppet/versions/1.0.0/providers/virtualbox.box</url>
|
||||
<esxi_url>https://app.vagrantup.com/redwiz666/boxes/ubuntu-16.04-64-puppet/versions/1.0.0/providers/vmware_esxi.box</esxi_url>
|
||||
<ovirt_template>debian_server</ovirt_template>
|
||||
|
||||
<reference>https://atlas.hashicorp.com/puppetlabs</reference>
|
||||
<software_license>various</software_license>
|
||||
</base>
|
||||
@@ -3,6 +3,7 @@ require_relative '../../../../../lib/objects/local_string_encoder.rb'
|
||||
class AccountGenerator < StringEncoder
|
||||
attr_accessor :username
|
||||
attr_accessor :password
|
||||
attr_accessor :groups
|
||||
attr_accessor :super_user
|
||||
attr_accessor :strings_to_leak
|
||||
attr_accessor :leaked_filenames
|
||||
@@ -13,6 +14,7 @@ class AccountGenerator < StringEncoder
|
||||
self.module_name = 'Account Generator / Builder'
|
||||
self.username = ''
|
||||
self.password = ''
|
||||
self.groups = []
|
||||
self.super_user = ''
|
||||
self.strings_to_leak = []
|
||||
self.data_to_leak = []
|
||||
@@ -23,6 +25,7 @@ class AccountGenerator < StringEncoder
|
||||
account_hash = {}
|
||||
account_hash['username'] = self.username
|
||||
account_hash['password'] = self.password
|
||||
account_hash['groups'] = self.groups
|
||||
account_hash['super_user'] = self.super_user
|
||||
account_hash['strings_to_leak'] = self.strings_to_leak
|
||||
account_hash['leaked_filenames'] = self.leaked_filenames
|
||||
@@ -37,6 +40,7 @@ class AccountGenerator < StringEncoder
|
||||
['--data_to_leak', GetoptLong::OPTIONAL_ARGUMENT],
|
||||
['--username', GetoptLong::REQUIRED_ARGUMENT],
|
||||
['--password', GetoptLong::REQUIRED_ARGUMENT],
|
||||
['--groups', GetoptLong::REQUIRED_ARGUMENT],
|
||||
['--super_user', GetoptLong::REQUIRED_ARGUMENT]]
|
||||
end
|
||||
|
||||
@@ -47,6 +51,8 @@ class AccountGenerator < StringEncoder
|
||||
self.username << arg;
|
||||
when '--password'
|
||||
self.password << arg;
|
||||
when '--groups'
|
||||
self.groups << arg;
|
||||
when '--super_user'
|
||||
self.super_user << arg;
|
||||
when '--strings_to_leak'
|
||||
@@ -61,6 +67,7 @@ class AccountGenerator < StringEncoder
|
||||
def encoding_print_string
|
||||
'username: ' + self.username.to_s + print_string_padding +
|
||||
'password: ' + self.password.to_s + print_string_padding +
|
||||
'groups: ' + self.groups.to_s + print_string_padding +
|
||||
'super_user: ' + self.super_user.to_s + print_string_padding +
|
||||
'strings_to_leak: ' + self.strings_to_leak.to_s + print_string_padding +
|
||||
'leaked_filenames: ' + self.leaked_filenames.to_s + print_string_padding +
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
<read_fact>username</read_fact>
|
||||
<read_fact>password</read_fact>
|
||||
<read_fact>groups</read_fact>
|
||||
<read_fact>super_user</read_fact>
|
||||
<read_fact>strings_to_leak</read_fact>
|
||||
<read_fact>leaked_filenames</read_fact>
|
||||
@@ -27,6 +28,8 @@
|
||||
<default_input into="password">
|
||||
<generator type="password_generator"/>
|
||||
</default_input>
|
||||
<default_input into="groups">
|
||||
</default_input>
|
||||
<default_input into="super_user">
|
||||
<value>false</value>
|
||||
</default_input>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Usually SecGen modules can be used without dependencies on anything specific being present in the scenario definition (other than ensuring conflicts don't exclude the module); any dependencies are typically automatically resolved by adding modules to the current system VM. However, **Hackerbot configs are closely tied to their scenarios**, as Hackerbot interacts with multiple VMs expecting specific modules to be deployed on each system.
|
||||
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/ruby
|
||||
require_relative '../../../../../../lib/objects/local_hackerbot_config_generator.rb'
|
||||
|
||||
class HB < HackerbotConfigGenerator
|
||||
|
||||
attr_accessor :server_ip
|
||||
|
||||
def initialize
|
||||
super
|
||||
self.module_name = 'Hackerbot Config Generator'
|
||||
self.title = 'Lab'
|
||||
|
||||
self.local_dir = File.expand_path('../../',__FILE__)
|
||||
self.templates_path = "#{self.local_dir}/templates/"
|
||||
self.config_template_path = "#{self.local_dir}/templates/lab.xml.erb"
|
||||
self.html_template_path = "#{self.local_dir}/templates/labsheet.html.erb"
|
||||
|
||||
self.server_ip = []
|
||||
end
|
||||
|
||||
def get_options_array
|
||||
super + [['--server_ip', GetoptLong::REQUIRED_ARGUMENT]]
|
||||
end
|
||||
|
||||
def process_options(opt, arg)
|
||||
super
|
||||
case opt
|
||||
when '--server_ip'
|
||||
self.server_ip << arg;
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
HB.new.run
|
||||
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<generator xmlns="http://www.github/cliffe/SecGen/generator"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.github/cliffe/SecGen/generator">
|
||||
<name>Hackerbot config for an access controls lab</name>
|
||||
<author>Z. Cliffe Schreuders</author>
|
||||
<module_license>GPLv3</module_license>
|
||||
<description>Generates a config file for a hackerbot for an integrity lab.
|
||||
Topics covered: .</description>
|
||||
|
||||
<type>hackerbot_config</type>
|
||||
<platform>linux</platform>
|
||||
|
||||
<read_fact>accounts</read_fact>
|
||||
<read_fact>flags</read_fact>
|
||||
<read_fact>root_password</read_fact>
|
||||
|
||||
<!--TODO: require input, such as accounts, or fail?-->
|
||||
|
||||
<default_input into="accounts">
|
||||
<generator type="account">
|
||||
<input into="username">
|
||||
<value>vagrant</value>
|
||||
</input>
|
||||
</generator>
|
||||
</default_input>
|
||||
|
||||
<default_input into="flags">
|
||||
<generator type="flag_generator"/>
|
||||
<generator type="flag_generator"/>
|
||||
<generator type="flag_generator"/>
|
||||
<generator type="flag_generator"/>
|
||||
<generator type="flag_generator"/>
|
||||
<!-- <generator type="flag_generator"/> -->
|
||||
</default_input>
|
||||
|
||||
<default_input into="root_password">
|
||||
<value>puppet</value>
|
||||
</default_input>
|
||||
|
||||
<output_type>hackerbot</output_type>
|
||||
|
||||
</generator>
|
||||
@@ -0,0 +1,29 @@
|
||||
<html>
|
||||
<head>
|
||||
<title><%= self.title %></title>
|
||||
</head>
|
||||
<body>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="css/github-markdown.css">
|
||||
<style>
|
||||
.markdown-body {
|
||||
box-sizing: border-box;
|
||||
min-width: 200px;
|
||||
max-width: 980px;
|
||||
margin: 0 auto;
|
||||
padding: 45px;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.markdown-body {
|
||||
padding: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<article class="markdown-body">
|
||||
|
||||
<%= self.html_rendered %>
|
||||
|
||||
</article>
|
||||
<script src="js/code-prettify/loader/run_prettify.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,4 @@
|
||||
## License
|
||||
This lab by [*Z. Cliffe Schreuders*](http://z.cliffe.schreuders.org) at Leeds Beckett University is licensed under a [*Creative Commons Attribution-ShareAlike 3.0 Unported License*](http://creativecommons.org/licenses/by-sa/3.0/deed.en_GB).
|
||||
|
||||
Included software source code is also licensed under the GNU General Public License, either version 3 of the License, or (at your option) any later version.
|
||||
@@ -0,0 +1,270 @@
|
||||
## Introduction to access control
|
||||
|
||||
*Access control* enforces *authorisation* by determining and enforcing which actions are allowed. Some terminology: a *subject* is an active entity taking actions, such as a user or program, and an *object* is the (often passive) resource that can be accessed, such as a file or network resource. Access control mediates all subjects' access to objects by enforcing a security policy, limiting which actions are and are not allowed. The *policy* expresses what is allowed, either formally or informally as a set of rules.
|
||||
|
||||
An access control *mechanism* is the code or thing that enforces a policy. An access control *model* is a way of representing and reasoning about a policy or types of policy.
|
||||
|
||||
## Unix file permissions and inodes
|
||||
|
||||
The traditional Unix security model is based on the *discretionary access control (DAC)* model, which enables users to configure who can access the resources that they "own". Each user can control which other users can access the files that they create. This enables users to grant permissions, without involving a system admin. This is the type of security that has traditionally been built into most consumer OSs such as Windows and Unix.
|
||||
|
||||
Unix file permissions uses an abbreviated (simplified) form of access control list (ACL). A (full) ACL involves attaching a list of every subject and what they can do to each file (this is how Windows manages file access). For example, a file may have this ACL: "Joe can read, Frank can write, Alice can read, and Eve can read".
|
||||
|
||||
Unix simplifies permissions by only defining rules for these three kinds of subjects:
|
||||
- **u**: The **u**ser that owns the file
|
||||
- **g**: The file's **g**roup
|
||||
- **o**: All **o**ther users
|
||||
|
||||
Open a terminal console.
|
||||
|
||||
Use the `ls` [^1] command to ==display the permissions for a file== (the details of the `ls` executable program itself):
|
||||
|
||||
```bash
|
||||
ls -l /bin/ls
|
||||
```
|
||||
|
||||
`
|
||||
-rwxr-xr-x 1 root root 130736 Feb 22 2017 /bin/ls
|
||||
`
|
||||
|
||||
The `-l` flag instructs `ls` to provide this detailed output.
|
||||
|
||||
The first part of the output contains the Unix file permissions for the file: what access the user (rwx), group (r-x), and other (r-x) are authorised.
|
||||
|
||||
The meaning of these letters is fairly self evident, but does change meaning slightly depending on whether it refers to a normal file or a directory (which is really just a special kind of file).
|
||||
|
||||
The meaning for a regular file (as is the case for /bin/ls):
|
||||
- **r**: Read the contents of the file
|
||||
- **w**: Change the contents of the file
|
||||
- **x**: Execute the file as a process (The first few bytes describe what type of executable it is, a program or a script)
|
||||
|
||||
For a directory:
|
||||
- **r**: See what files are in the directory
|
||||
- **w**: Add, rename, or delete names from the directory
|
||||
- **x**: 'stat' the file (view the file owners and sizes, cd into the directory, and access files within)
|
||||
- **t** (in place of x), AKA the "sticky bit": write is not enough to delete a file from the directory, in this case you also need to own the file
|
||||
|
||||
The rest of the output from ls describes how many names/hard links the file has (1), who owns the file: the user (root) and group (root) associated with the file, the file size in bytes (130736 bytes in the example above), the last access date, and finally the path and name of the file.
|
||||
|
||||
The permissions for each file are stored in the file's inode. An inode is a data structure in Unix filesystems that defines a file. An inode includes an inode number, and defines the location of the file on disk, along with attributes including the Unix file permissions, and access times for the file.
|
||||
|
||||
==View the **inode number** for this file:==
|
||||
|
||||
```bash
|
||||
ls -i /bin/ls
|
||||
```
|
||||
|
||||
Note that the inode does **not** contain the file's name, rather a directory can contain names that point to inodes. It is therefore possible to create two names (aka hard links) that point to the same file.
|
||||
|
||||
==Create a hard link to the `ls` program:==
|
||||
|
||||
```bash
|
||||
sudo ln /bin/ls /tmp/ls
|
||||
```
|
||||
|
||||
Now ==view the details== for your new filename, /tmp/ls:
|
||||
|
||||
```bash
|
||||
ls -l /tmp/ls
|
||||
```
|
||||
|
||||
==How many hard links does this report?== ==What are the file ownership and permissions associated with the new name?==
|
||||
|
||||
View the inode number for this file:
|
||||
|
||||
```bash
|
||||
ls -i /tmp/ls
|
||||
```
|
||||
|
||||
*The inode matches.*
|
||||
|
||||
There is *only one file*, but that data can now be accessed using two different names /tmp/ls and /bin/ls. If the /tmp/ls file was edited, the /bin/ls command would also change.
|
||||
|
||||
Deleting one of the names simply decrements the link counter. Only when that reaches 0 is the inode actually removed. ==Run:==
|
||||
|
||||
```bash
|
||||
sudo rm /tmp/ls
|
||||
```
|
||||
|
||||
In addition to hard links, there are also symbolic or soft links. ==Let's create a symlink now.==
|
||||
|
||||
```bash
|
||||
ln -s /bin/ls /tmp/ls
|
||||
```
|
||||
|
||||
Unlike hard links, symbolic links do not contain the information of the file they are linked to; a symbolic link is similar to a Windows shortcut, it simply points to another file on the system - this allows them to link to directories and remote files, in a way that hard links cannot. If the original file is deleted, the symlink becomes unusual, whereas the data of the target file is preserved in the case of a hard link.
|
||||
|
||||
==View the details== for this file:
|
||||
|
||||
```bash
|
||||
ls -l /tmp/ls
|
||||
```
|
||||
|
||||
The first letter is an `l` where it hand been an `-` before, representing the fact that this file is a symbolic link file. The very last part indicates what this file is linked to (in this case, /bin/ls)
|
||||
|
||||
Now, ==try to remove this symlink as another user.==
|
||||
|
||||
```bash
|
||||
sudo -u <%= $second_user %> rm /tmp/ls
|
||||
```
|
||||
|
||||
Permission denied! Interestingly, in this case as a normal user we can create the symlink to /bin/ls in the shared directory, but other user cannot then delete that link since the sticky bit is set for the /tmp/ directory. ==Run:==
|
||||
|
||||
```bash
|
||||
ls -ld /tmp/
|
||||
```
|
||||
|
||||
Note the `t` in the permissions, and refer to the meaning described above.
|
||||
|
||||
==Log Book Questions: What is this directory used for? Why do you think the /tmp/ directory has the sticky bit set -- what does this stop users from doing to each other? How is this related to security?==
|
||||
|
||||
You can ==delete the link as root:==
|
||||
|
||||
```bash
|
||||
sudo rm /tmp/ls
|
||||
```
|
||||
|
||||
The stat command can be used to display further information from the inode. ==Run:==
|
||||
|
||||
```bash
|
||||
stat /bin/ls
|
||||
```
|
||||
|
||||
==Look through this information==. Note that the output includes the access rights, along with the last time the file was accessed, modified, and when the inode was last changed.
|
||||
|
||||
The output from stat includes the format that the information is stored as, along with a more "human readable" output. As we know, user accounts are referred to by UIDs by the system, in this case the UID is 0, as the file is owned by the root user. Similarly, groups are identified by GID, in this case also 0. The actual permissions are stored as four octets (digits 0-7), in this case `0755`. This translates to the (now familiar) human-friendly output, `-rwxr-xr-x`. For now we will ignore the first octet, this is normally 0, we will come back to the special meaning of this later.
|
||||
|
||||
Each of the other three octets simply represents the binary for rwx, each represented as a 0 or a 1. The first of the three represents the **u**ser, then the **g**roup, then the **o**ther permission.
|
||||
|
||||
An easy and quick way to do the conversion is to simply remember:
|
||||
|
||||
- r = 4
|
||||
- w = 2
|
||||
- x = 1
|
||||
|
||||
And add them together to produce each of the three octets.
|
||||
|
||||
So for example, rwx = binary 111 = (4 + 2 + 1) = 7.
|
||||
|
||||
Likewise, r-x = binary 101 = (4 + 1) = 5.
|
||||
|
||||
Therefore, `-rwxr-xr-x` = 755.
|
||||
|
||||
## Changing file permissions on a Linux system
|
||||
|
||||
==Open a second console/Tab.==
|
||||
> In Konsole, press Ctrl+T to open another tab
|
||||
|
||||
==Switch to your second user account:==
|
||||
|
||||
```bash
|
||||
su - <%= $second_user %>
|
||||
```
|
||||
|
||||
> Do not login as root, instead use sudo or su as required.
|
||||
|
||||
Create a file named "mysecrets" in your <%= $second_user %>'s home directory:[^2]
|
||||
|
||||
```bash
|
||||
cat > ~/mysecrets
|
||||
```
|
||||
|
||||
Enter a number of lines of content. Press Ctrl-D when finished entering a "secret".
|
||||
|
||||
Your first aim is to ensure your "mysecrets" file is not visible to other users on the same system.
|
||||
|
||||
First ==view the permissions== of your newly created file:
|
||||
|
||||
```bash
|
||||
ls ~/mysecrets
|
||||
```
|
||||
|
||||
Oh no! It's not so secret!
|
||||
|
||||
What kind of access do other users on the system have to this file?
|
||||
|
||||
The chmod command can be used to set permissions on a file. chmod can set permissions based on absolute octal values, or relative changes.
|
||||
|
||||
So for example, you could use chmod to set permissions on a file based on octet:
|
||||
|
||||
> 770 would give the owner and group rwx, and others no permissions
|
||||
>
|
||||
> Example: chmod 770 /home/tmp/somefile
|
||||
|
||||
Or you can make relative changes:
|
||||
|
||||
> u+x would add the owner (user) the ability to execute the file
|
||||
>
|
||||
> Example: `chmod u+x /home/tmp/somefile`
|
||||
>
|
||||
> Likewise, o-w would removes *other*'s ability to write to the file
|
||||
>
|
||||
> Example: chmod o-w /home/tmp/somefile
|
||||
|
||||
==Use chmod to grant yourself read-write permission to your mysecrets file, and everyone else no permissions to the file==:
|
||||
|
||||
```bash
|
||||
chmod *XXX* ~/mysecrets
|
||||
```
|
||||
|
||||
> Where *XXX* is three octets that grants the appropriate access.
|
||||
|
||||
> Test whether you have correctly set permissions. Switch back to the <%= $main_user %> console and test that <%= $main_user %> cannot access the file:
|
||||
|
||||
```bash
|
||||
less /home/student/mysecrets`
|
||||
```
|
||||
|
||||
## `umask`
|
||||
|
||||
Remember that our newly created file started with permissions that meant that everyone could read the file. This can be avoided by setting the **u**ser file-creation mode **mask** (**umask**). Every process has a umask: an octal that determines the permissions of newly created files. It works by removing permissions from the default `666` for files and `777` for new executables (based on a logical NOT). That is, a umask of `000` would result in new files with permissions `666`. A umask of `022` (which is the default value) gives `644`, that is `rw- -r- -r-`.
|
||||
|
||||
The umask Bash built in (or system call) can be used to set the umask for the current process.
|
||||
|
||||
Check the current umask value:
|
||||
|
||||
```bash
|
||||
umask
|
||||
```
|
||||
|
||||
Using the umask builtin command, set your umask so that new files are only rw accessible by you (but not to your group or others):
|
||||
|
||||
```bash
|
||||
umask *XXX*
|
||||
```
|
||||
|
||||
> Where XXX is the new umask to use.
|
||||
|
||||
Test your new umask value by creating a new file and checking its permissions:
|
||||
|
||||
```bash
|
||||
touch *newfilename*
|
||||
|
||||
ls -l *newfilename*
|
||||
```
|
||||
|
||||
> Do the permissions read `rw-------`? If not, change the umask and try again.
|
||||
|
||||
Figure out how to (and do) make that setting apply every time you login.
|
||||
|
||||
> Hint: try Googling bash login or startup config
|
||||
|
||||
What would be a safe umask for a shared Linux system? Justify your decision.
|
||||
|
||||
## Conclusion
|
||||
|
||||
At this point you have:
|
||||
|
||||
- Learned about file permissions, hard links, and inodes
|
||||
|
||||
- Learned about octal representations of permissions
|
||||
|
||||
- Changed Unix file permissions to grant access to specific users and groups, using chmod
|
||||
|
||||
- Used umask to change the permissions applied to new files
|
||||
|
||||
Well done!
|
||||
|
||||
[^1]: The name `ls` is from the old Multix command which was named after "list segments", although it can be thought of as "list" (since the term "segment" is no longer meaningful for Unix), it is similar in use to the dir command on Windows.
|
||||
|
||||
[^2]: The `~` character is interpreted by Bash as the location of your own home directory, such as /home/*dropbear*/
|
||||
@@ -0,0 +1,34 @@
|
||||
# Access Controls and Linux File Permissions
|
||||
|
||||
## Getting started
|
||||
### VMs in this lab
|
||||
|
||||
==Start these VMs== (if you haven't already):
|
||||
- hackerbot_server (leave it running, you don't log into this)
|
||||
- desktop (you can sudo to get superuser access)
|
||||
- server (<%= $server_ip %>, you can ssh to this machine, but you don't have superuser access)
|
||||
|
||||
### Your login details for the "desktop" and "server" VMs
|
||||
User 1: <%= $main_user %>
|
||||
Password: tiaspbiqe2r (**t**his **i**s **a** **s**ecure **p**assword **b**ut **i**s **q**uite **e**asy **2** **r**emember)
|
||||
|
||||
User 2: <%= $second_user %>
|
||||
Password: <%= $second_password %>
|
||||
|
||||
|
||||
You won't login to the hackerbot_server, but the VM needs to be running to complete the lab.
|
||||
|
||||
### For marks in the module
|
||||
1. **You need to submit flags**. Note that the flags and the challenges in your VMs are different to other's in the class. Flags will be revealed to you as you complete challenges throughout the module. Flags look like this: ==flag{*somethingrandom*}==. Follow the link on the module page to submit your flags.
|
||||
2. **You need to document the work and your solutions in a Log Book**. This needs to include screenshots (including the flags) of how you solved each Hackerbot challenge and a writeup describing your solution to each challenge, and answering any "Log Book Questions". The Log Book will be submitted later in the semester.
|
||||
|
||||
## Meet Hackerbot!
|
||||

|
||||
|
||||
This exercise involves interacting with Hackerbot, a chatbot who will attack your system. If you satisfy Hackerbot by completing the challenges she will reveal flags to you.
|
||||
|
||||
> If Hackerbot seems to be waiting or halted, simply say 'hi'
|
||||
|
||||
Work through the below exercises, completing the Hackerbot challenges as noted.
|
||||
|
||||
---
|
||||
@@ -0,0 +1,300 @@
|
||||
<%
|
||||
require 'json'
|
||||
require 'securerandom'
|
||||
require 'digest/sha1'
|
||||
require 'fileutils'
|
||||
require 'erb'
|
||||
|
||||
if self.accounts.empty?
|
||||
abort('Sorry, you need to provide an account')
|
||||
end
|
||||
|
||||
$first_account = JSON.parse(self.accounts.first)
|
||||
$main_user = $first_account['username'].to_s
|
||||
$main_user_pass = $first_account['password'].to_s
|
||||
|
||||
$second_account = JSON.parse(self.accounts[1])
|
||||
$second_user = $second_account['username'].to_s
|
||||
$second_password = $second_account['password'].to_s
|
||||
|
||||
$third_account = JSON.parse(self.accounts[2])
|
||||
$third_user = $third_account['username'].to_s
|
||||
$third_password = $third_account['password'].to_s
|
||||
|
||||
|
||||
$server_ip = self.server_ip.first
|
||||
$root_password = self.root_password
|
||||
$flags = self.flags
|
||||
|
||||
REQUIRED_FLAGS = 5
|
||||
while $flags.length < REQUIRED_FLAGS
|
||||
$flags << "flag{#{SecureRandom.hex}}"
|
||||
Print.err "Warning: Not enough flags provided to hackerbot_config generator, some flags won't be tracked/marked!"
|
||||
end
|
||||
|
||||
def get_binding
|
||||
binding
|
||||
end
|
||||
%>
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<hackerbot
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.github/cliffe/SecGen/hackerbot">
|
||||
<!--<hackerbot xmlns="http://www.github/cliffe/SecGen/hackerbotz"-->
|
||||
|
||||
<name>Hackerbot</name>
|
||||
|
||||
<AIML_chatbot_rules>config/AIML</AIML_chatbot_rules>
|
||||
|
||||
<!--Method for gaining shell access, can be overwritten per-attack-->
|
||||
<get_shell>sshpass -p <%= $root_password %> ssh -oStrictHostKeyChecking=no root@{{chat_ip_address}} /bin/bash</get_shell>
|
||||
|
||||
<messages>
|
||||
<show_attack_numbers />
|
||||
|
||||
<greeting>Hi there. Today I'm your boss of sorts. I need you to config the security of your desktop. Help out and I'll give you some flags.</greeting>
|
||||
|
||||
<!--Must provide alternatives for each message-->
|
||||
<say_ready>When you are ready, simply say 'ready'.</say_ready>
|
||||
<say_ready>'Ready'?</say_ready>
|
||||
<next>Ok, I'll do what I can to move things along...</next>
|
||||
<next>Moving things along to the next one...</next>
|
||||
<previous>Ok, I'll do what I can to back things up...</previous>
|
||||
<previous>Ok, backing up.</previous>
|
||||
<goto>Ok, skipping it along.</goto>
|
||||
<goto>Let me see what I can do to goto that attack.</goto>
|
||||
<last_attack>That was the last one for now. You can rest easy, until next time... (End.)</last_attack>
|
||||
<last_attack>That was the last one. Game over?</last_attack>
|
||||
<first_attack>You are back to the beginning!</first_attack>
|
||||
<first_attack>This is where it all began.</first_attack>
|
||||
<getting_shell>Doing my thing...</getting_shell>
|
||||
<getting_shell>Here we go...</getting_shell>
|
||||
<got_shell>...</got_shell>
|
||||
<got_shell>....</got_shell>
|
||||
<repeat>Let me know when you are 'ready', if you want to move on say 'next', or 'previous' and I'll move things along.</repeat>
|
||||
<repeat>Say 'ready', 'next', or 'previous'.</repeat>
|
||||
|
||||
<!--Single responses:-->
|
||||
<help>I am waiting for you to say 'ready', 'next', 'previous', 'list', 'goto *X*', or 'answer *X*'</help>
|
||||
<say_answer>Say "The answer is *X*".</say_answer>
|
||||
<no_quiz>There is no question to answer</no_quiz>
|
||||
<correct_answer>Correct</correct_answer>
|
||||
<incorrect_answer>Incorrect</incorrect_answer>
|
||||
<invalid>That's not possible.</invalid>
|
||||
<non_answer>Wouldn't you like to know.</non_answer>
|
||||
|
||||
<!--can be overwritten per-attack-->
|
||||
<shell_fail_message>Oh no. Failed to get shell... You need to let us in.</shell_fail_message>
|
||||
</messages>
|
||||
|
||||
<tutorial_info>
|
||||
<title>Authentication</title>
|
||||
<tutorial><%= ERB.new(File.read self.templates_path + 'intro.md.erb').result(self.get_binding) %></tutorial>
|
||||
<footer>
|
||||
<%= File.read self.templates_path + 'resources.md.erb' %>
|
||||
|
||||
<%= File.read self.templates_path + 'license.md.erb' %>
|
||||
|
||||
Randomised instance generated by [SecGen](http://github.com/cliffe/SecGen) (<%= Time.new.to_s %>)
|
||||
</footer>
|
||||
|
||||
<provide_tutorial>true</provide_tutorial>
|
||||
|
||||
</tutorial_info>
|
||||
|
||||
|
||||
<attack>
|
||||
<% $rand_group = "group#{SecureRandom.hex(3)}" %>
|
||||
<prompt>Create a new group, <%= $rand_group %>, on your desktop.</prompt>
|
||||
|
||||
<post_command>grep ^<%= $rand_group %> /etc/group; echo -$?-</post_command>
|
||||
|
||||
<condition>
|
||||
<output_matches>-0-</output_matches>
|
||||
<message>:) Well done! <%= $flags.pop %></message>
|
||||
<trigger_next_attack />
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>-1-</output_matches>
|
||||
<message>:( It doesn't look like the group exists.</message>
|
||||
</condition>
|
||||
<else_condition>
|
||||
<message>:( Something was not right</message>
|
||||
</else_condition>
|
||||
|
||||
<tutorial><%= ERB.new(File.read self.templates_path + 'access_controls.md.erb').result(self.get_binding) %></tutorial>
|
||||
|
||||
</attack>
|
||||
|
||||
<attack>
|
||||
<prompt>Add yourself (<%= $main_user %>) to the <%= $rand_group %>, on your desktop.</prompt>
|
||||
|
||||
<post_command>groups <%= $main_user %>; id <%= $main_user %> -Gn; echo -$?-</post_command>
|
||||
|
||||
<condition>
|
||||
<output_matches><%= $rand_group %></output_matches>
|
||||
<message>:) Well done! <%= $flags.pop %></message>
|
||||
<trigger_next_attack />
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>-0-</output_matches>
|
||||
<message>:( I can't see the group assigned to the user.</message>
|
||||
</condition>
|
||||
<else_condition>
|
||||
<message>:( Something was not right</message>
|
||||
</else_condition>
|
||||
|
||||
</attack>
|
||||
|
||||
<attack>
|
||||
<% $rand_secret1 = "secret#{SecureRandom.hex(3)}" %>
|
||||
<% $rand_perms1 = "#{rand < 0.5 ? 'r' : '-'}#{rand < 0.5 ? 'w' : '-'}#{rand < 0.2 ? 'x' : '-'}" %>
|
||||
<% $rand_perms1_other = "------" %>
|
||||
<% $rand_secret_file1 = "/home/#{$main_user}/secret#{SecureRandom.hex(3)}" %>
|
||||
<prompt>Create a file, <%= $rand_secret_file1 %>, containing the string <%= $rand_secret1 %>. Make sure the file is owned by <%= $main_user %>, with <%= $rand_perms1 %><%= $rand_perms1_other %> permissions </prompt>
|
||||
|
||||
<post_command>ls -l <%= $rand_secret_file1 %>; echo -$?-</post_command>
|
||||
|
||||
<condition>
|
||||
<output_matches>^-<%= $rand_perms1 %><%= $rand_perms1_other %> [0-9]+ <%= $main_user %></output_matches>
|
||||
<message>:) Well done! <%= $flags.pop %></message>
|
||||
<trigger_next_attack />
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>-[1-9]+-</output_matches>
|
||||
<message>:( It looks like the file might not exist.</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>^-<%= $rand_perms1 %>.* [0-9]+</output_matches>
|
||||
<message>:( Looks like the file permissions for groups/other is incorrect</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>^-<%= $rand_perms1 %><%= $rand_perms1_other %></output_matches>
|
||||
<message>:( Almost there, is the ownership correct?</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>^-<%= $rand_perms1 %><%= $rand_perms1_other %>\+</output_matches>
|
||||
<message>:( Almost there. Make sure you are not using extended ACLs.</message>
|
||||
</condition>
|
||||
<else_condition>
|
||||
<message>:( Something was not right</message>
|
||||
</else_condition>
|
||||
|
||||
</attack>
|
||||
|
||||
<attack>
|
||||
<% $rand_secret2 = "secret#{SecureRandom.hex(3)}" %>
|
||||
<% $rand_perms2 = "#{rand < 0.8 ? 'r' : '-'}#{rand < 0.8 ? 'w' : '-'}#{rand < 0.2 ? 'x' : '-'}" %>
|
||||
<% $rand_perms2_group = "#{rand < 0.8 ? 'r' : '-'}#{rand < 0.8 ? 'w' : '-'}#{rand < 0.2 ? 'x' : '-'}" %>
|
||||
<% $rand_perms2_other = "---" %>
|
||||
<% $rand_group2 = "#{rand < 0.5 ? 'staff' : 'team_one'}" %>
|
||||
<% $rand_secret_file2 = "/home/#{$second_user}/secret#{SecureRandom.hex(3)}" %>
|
||||
<prompt>Create a file, <%= $rand_secret_file2 %>, containing the string <%= $rand_secret2 %>. Make sure the file is owned by <%= $second_user %>, with <%= $rand_perms2 %><%= $rand_perms2_group %><%= $rand_perms2_other %> permissions, and assigned to the '<%= $rand_group2 %>' group.</prompt>
|
||||
|
||||
<post_command>ls -l <%= $rand_secret_file2 %>; echo -$?-</post_command>
|
||||
|
||||
<condition>
|
||||
<output_matches>^-<%= $rand_perms2 %><%= $rand_perms2_group %><%= $rand_perms2_other %> [0-9]+ <%= $second_user %> <%= $rand_group2 %></output_matches>
|
||||
<message>:) Well done! <%= $flags.pop %></message>
|
||||
<trigger_next_attack />
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>-[1-9]+-</output_matches>
|
||||
<message>:( It looks like the file might not exist.</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>^-<%= $rand_perms2 %><%= $rand_perms2_group %><%= $rand_perms2_other %></output_matches>
|
||||
<message>:( Almost there, is the ownership and group correct?</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>^-<%= $rand_perms2 %>.* [0-9]+</output_matches>
|
||||
<message>:( Looks like the file permissions for groups/other is incorrect</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>^-<%= $rand_perms2 %><%= $rand_perms2_group %><%= $rand_perms2_other %>\+</output_matches>
|
||||
<message>:( Almost there. Make sure you are not using extended ACLs.</message>
|
||||
</condition>
|
||||
<else_condition>
|
||||
<message>:( Something was not right</message>
|
||||
</else_condition>
|
||||
|
||||
</attack>
|
||||
|
||||
<attack>
|
||||
<% $rand_secret3 = "secret#{SecureRandom.hex(3)}" %>
|
||||
<% $rand_secret_file3 = "/home/#{$main_user}/secret#{SecureRandom.hex(3)}" %>
|
||||
<prompt>Create a file, <%= $rand_secret_file3 %>, containing the string <%= $rand_secret3 %>. Make sure the file is owned by <%= $main_user %>. Use a group to enable <%= $second_user %> to also read the file, but not write to it. Make sure <%= $third_user %> can't access the file.</prompt>
|
||||
|
||||
<!-- <get_shell>sshpass -p <%= $root_password %> ssh -oStrictHostKeyChecking=no root@<%= $server_ip %> /bin/bash</get_shell> -->
|
||||
|
||||
<post_command>sudo -u <%= $main_user %> grep <%= $rand_secret3 %> <%= $rand_secret_file3 %> >/dev/null; echo m-$?-; sudo -u <%= $second_user %> grep <%= $rand_secret3 %> <%= $rand_secret_file3 %> >/dev/null; echo s-$?-; sudo -u <%= $third_user %> grep <%= $rand_secret3 %> <%= $rand_secret_file3 %> >/dev/null; echo t-$?-; sudo -u <%= $third_user %> bash -c 'echo "hackerbot/<%= $third_user %> was here!" > <%= $rand_secret_file3 %>' >/dev/null; echo tw-$?-; ls -l <%= $rand_secret_file3 %> | grep +; echo f-$?- </post_command>
|
||||
|
||||
<condition>
|
||||
<output_matches>No such file or directory</output_matches>
|
||||
<message>:( It looks like the file might not exist.</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>m-0-.*s-0-.*t-2-.*f-1-</output_matches>
|
||||
<message>:) Well done! <%= $flags.pop %></message>
|
||||
<trigger_next_attack />
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>m-0-.*s-0-.*t-2-.*f-0-</output_matches>
|
||||
<message>:P Looks like you got all the file access working, but you are not supposed to use facls for this task!</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>tw-0-</output_matches>
|
||||
<message>:( Your file wasn't protected from <%= $third_user %>!</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>m-0-.*s-0-</output_matches>
|
||||
<message>:( Looks like <%= $main_user %> and <%= $second_user %> can access the file... Almost there. Make sure <%= $third_user %> doesn't have permission to access it.</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>t-0-</output_matches>
|
||||
<message>:( Looks like <%= $third_user %> can read the file... Use groups and set permissions to make sure they can't do so...</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>s-0-</output_matches>
|
||||
<message>:( Looks like <%= $second_user %> can access the file... Almost there...</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>s-2-</output_matches>
|
||||
<message>:( Looks like <%= $second_user %> can't access the file... Use groups and set permissions to make sure they can...</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>m-0-</output_matches>
|
||||
<message>:( Looks like <%= $main_user %> can access the file... Almost there...</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>m-1-|s-1-</output_matches>
|
||||
<message>:( Looks like the file has the wrong contents...</message>
|
||||
</condition>
|
||||
<else_condition>
|
||||
<message>:( Something was not right</message>
|
||||
</else_condition>
|
||||
|
||||
</attack>
|
||||
|
||||
<attack>
|
||||
|
||||
<prompt>There is a serious access control misconfiguration on your server. You may be able to get yourself root access and find some flags in a home directory. This is the end.</prompt>
|
||||
|
||||
<condition>
|
||||
<output_matches>.*</output_matches>
|
||||
<message>:)</message>
|
||||
<trigger_next_attack />
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>.*</output_matches>
|
||||
<message>:)</message>
|
||||
<trigger_next_attack />
|
||||
</condition>
|
||||
<else_condition>
|
||||
<message>:)</message>
|
||||
</else_condition>
|
||||
|
||||
</attack>
|
||||
|
||||
</hackerbot>
|
||||
@@ -0,0 +1,114 @@
|
||||
<html>
|
||||
<head>
|
||||
<title><%= self.title %></title>
|
||||
</head>
|
||||
<body>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="css/github-markdown.css">
|
||||
<style>
|
||||
.markdown-body {
|
||||
box-sizing: border-box;
|
||||
min-width: 200px;
|
||||
max-width: 980px;
|
||||
margin: 0 auto;
|
||||
padding: 45px;
|
||||
}
|
||||
.markdown-body h4[id^='hackerbot']:after {
|
||||
display: inline-block;
|
||||
float: right;
|
||||
content: url("images/skullandusb.svg");
|
||||
width: 30px;
|
||||
}
|
||||
article {
|
||||
float: right;
|
||||
width: calc(100% - 300px);
|
||||
}
|
||||
.toc {
|
||||
float: left;
|
||||
font-size: smaller;
|
||||
color: #1a1d22;
|
||||
width: 300px;
|
||||
position: fixed;
|
||||
height: calc(100% - 56px);
|
||||
overflow-y: scroll;
|
||||
font-family: sans-serif;
|
||||
margin-top: 50px;
|
||||
}
|
||||
.toc ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin-left: 1em;
|
||||
}
|
||||
.toc li { /* Space between menu items*/
|
||||
margin: 1em 0;
|
||||
}
|
||||
.toc a {
|
||||
color: #1a1d22;
|
||||
text-decoration: none;
|
||||
}
|
||||
.toc a:hover {
|
||||
color: #6c036d;
|
||||
text-decoration: none;
|
||||
}
|
||||
.toc a:visited {
|
||||
color: #1a1d22;
|
||||
text-decoration: none;
|
||||
}
|
||||
.markdown-body pre, .markdown-body code {
|
||||
background-color: #570138;
|
||||
color: whitesmoke;
|
||||
}
|
||||
.markdown-body img[alt="small-left"] {
|
||||
max-width: 100px;
|
||||
float: left;
|
||||
}
|
||||
.markdown-body img[alt="small-right"] {
|
||||
max-width: 100px;
|
||||
float: right;
|
||||
}
|
||||
.markdown-body img[alt="tiny-right"] {
|
||||
max-width: 30px;
|
||||
float: right;
|
||||
}
|
||||
.markdown-body img[alt="small"] {
|
||||
max-width: 100px;
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding: 15px;
|
||||
}
|
||||
mark {
|
||||
background-color: white;
|
||||
color: #5b29bd;
|
||||
font-weight: bolder;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.markdown-body {
|
||||
padding: 15px;
|
||||
min-width: 200px;
|
||||
max-width: 980px;
|
||||
}
|
||||
.toc {
|
||||
float: none;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
height: auto;
|
||||
}
|
||||
article {
|
||||
float: none;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
<div class="toc">
|
||||
<%= self.html_TOC_rendered %>
|
||||
</div>
|
||||
|
||||
<article class="markdown-body">
|
||||
<%= self.html_rendered %>
|
||||
</article>
|
||||
<script src="js/code-prettify/loader/run_prettify.js?autoload=true&skin=sunburst&lang=css"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,6 @@
|
||||
## License
|
||||
This lab by [*Z. Cliffe Schreuders*](http://z.cliffe.schreuders.org) at Leeds Beckett University is licensed under a [*Creative Commons Attribution-ShareAlike 3.0 Unported License*](http://creativecommons.org/licenses/by-sa/3.0/deed.en_GB).
|
||||
|
||||
Included software source code is also licensed under the GNU General Public License, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||

|
||||
@@ -0,0 +1,2 @@
|
||||
# Reading
|
||||
[Chapter 1 "Foundations of Security and Access Control in Computing": Benantar, M. (2006), Access Control Systems: Security, Identity Management and Trust Models, Springer. (ISBN-10: 0387004459)](https://www-dawsonera-com.ezproxy.leedsbeckett.ac.uk/readonline/9780387277165)
|
||||
@@ -0,0 +1,35 @@
|
||||
|
||||
# CONVERT THESE INTO HB CHALLENGES
|
||||
==Create a file "~/myshare", and grant everyone read-write access.==
|
||||
|
||||
> Test whether you have correctly set permissions.
|
||||
|
||||
==Create "mygroupshare", grant only read access to everyone in your group.==
|
||||
|
||||
> Test whether you have correctly set permissions.
|
||||
|
||||
Create a new group called "staff", and create a file that you and the other user can collaborate on (both edit).
|
||||
|
||||
> Hint, you should both be added to the group. You may require root access for this task. Your classmate may want to ssh to your system.
|
||||
>
|
||||
> Test whether you have correctly set permissions. Both users should be able to edit the file, yet other users should not have write access.
|
||||
|
||||
Read and write to the shared files created by others, for example:
|
||||
|
||||
```bash
|
||||
cat /home/*dropbear*/myshare
|
||||
```
|
||||
|
||||
**Challenge**:
|
||||
|
||||
```bash
|
||||
mkdir test
|
||||
```
|
||||
|
||||
```bash
|
||||
touch test/test1 test/test2 test/test3
|
||||
```
|
||||
|
||||
> Use a single chmod command to recursively set the permissions for all files contained in the new "test" directory.
|
||||
>
|
||||
> Hint: `man chmod`
|
||||
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/ruby
|
||||
require_relative '../../../../../../lib/objects/local_hackerbot_config_generator.rb'
|
||||
|
||||
class HB < HackerbotConfigGenerator
|
||||
|
||||
attr_accessor :server_ip
|
||||
|
||||
def initialize
|
||||
super
|
||||
self.module_name = 'Hackerbot Config Generator'
|
||||
self.title = 'Lab'
|
||||
|
||||
self.local_dir = File.expand_path('../../',__FILE__)
|
||||
self.templates_path = "#{self.local_dir}/templates/"
|
||||
self.config_template_path = "#{self.local_dir}/templates/lab.xml.erb"
|
||||
self.html_template_path = "#{self.local_dir}/templates/labsheet.html.erb"
|
||||
|
||||
self.server_ip = []
|
||||
end
|
||||
|
||||
def get_options_array
|
||||
super + [['--server_ip', GetoptLong::REQUIRED_ARGUMENT]]
|
||||
end
|
||||
|
||||
def process_options(opt, arg)
|
||||
super
|
||||
case opt
|
||||
when '--server_ip'
|
||||
self.server_ip << arg;
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
HB.new.run
|
||||
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<generator xmlns="http://www.github/cliffe/SecGen/generator"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.github/cliffe/SecGen/generator">
|
||||
<name>Hackerbot config for an access control lab</name>
|
||||
<author>Z. Cliffe Schreuders</author>
|
||||
<module_license>GPLv3</module_license>
|
||||
<description>Generates a config file for a hackerbot for an integrity lab.
|
||||
Topics covered: .</description>
|
||||
|
||||
<type>hackerbot_config</type>
|
||||
<platform>linux</platform>
|
||||
|
||||
<read_fact>accounts</read_fact>
|
||||
<read_fact>flags</read_fact>
|
||||
<read_fact>root_password</read_fact>
|
||||
|
||||
<!--TODO: require input, such as accounts, or fail?-->
|
||||
|
||||
<default_input into="accounts">
|
||||
<generator type="account">
|
||||
<input into="username">
|
||||
<value>vagrant</value>
|
||||
</input>
|
||||
</generator>
|
||||
</default_input>
|
||||
|
||||
<default_input into="flags">
|
||||
<generator type="flag_generator"/>
|
||||
<generator type="flag_generator"/>
|
||||
</default_input>
|
||||
|
||||
<default_input into="root_password">
|
||||
<value>puppet</value>
|
||||
</default_input>
|
||||
|
||||
<output_type>hackerbot</output_type>
|
||||
|
||||
</generator>
|
||||
@@ -0,0 +1,29 @@
|
||||
<html>
|
||||
<head>
|
||||
<title><%= self.title %></title>
|
||||
</head>
|
||||
<body>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="css/github-markdown.css">
|
||||
<style>
|
||||
.markdown-body {
|
||||
box-sizing: border-box;
|
||||
min-width: 200px;
|
||||
max-width: 980px;
|
||||
margin: 0 auto;
|
||||
padding: 45px;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.markdown-body {
|
||||
padding: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<article class="markdown-body">
|
||||
|
||||
<%= self.html_rendered %>
|
||||
|
||||
</article>
|
||||
<script src="js/code-prettify/loader/run_prettify.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,4 @@
|
||||
## License
|
||||
This lab by [*Z. Cliffe Schreuders*](http://z.cliffe.schreuders.org) at Leeds Beckett University is licensed under a [*Creative Commons Attribution-ShareAlike 3.0 Unported License*](http://creativecommons.org/licenses/by-sa/3.0/deed.en_GB).
|
||||
|
||||
Included software source code is also licensed under the GNU General Public License, either version 3 of the License, or (at your option) any later version.
|
||||
@@ -0,0 +1,29 @@
|
||||
# Mandatory Access Controls: AppArmor
|
||||
|
||||
## Getting started
|
||||
### VMs in this lab
|
||||
|
||||
==Start these VMs== (if you haven't already):
|
||||
- hackerbot_server (leave it running, you don't log into this)
|
||||
- desktop (you can sudo to get superuser access)
|
||||
|
||||
### Your login details for the "desktop" and "server" VMs
|
||||
User: <%= $main_user %>
|
||||
Password: tiaspbiqe2r (**t**his **i**s **a** **s**ecure **p**assword **b**ut **i**s **q**uite **e**asy **2** **r**emember)
|
||||
|
||||
You won't login to the hackerbot_server, but the VM needs to be running to complete the lab.
|
||||
|
||||
### For marks in the module
|
||||
1. **You need to submit flags**. Note that the flags and the challenges in your VMs are different to other's in the class. Flags will be revealed to you as you complete challenges throughout the module. Flags look like this: ==flag{*somethingrandom*}==. Follow the link on the module page to submit your flags.
|
||||
2. **You need to document the work and your solutions in a Log Book**. This needs to include screenshots (including the flags) of how you solved each Hackerbot challenge and a writeup describing your solution to each challenge, and answering any "Log Book Questions". The Log Book will be submitted later in the semester.
|
||||
|
||||
## Meet Hackerbot!
|
||||

|
||||
|
||||
This exercise involves interacting with Hackerbot, a chatbot who will attack your system. If you satisfy Hackerbot by completing the challenges she will reveal flags to you.
|
||||
|
||||
> If Hackerbot seems to be waiting or halted, simply say 'hi'
|
||||
|
||||
Work through the below exercises, completing the Hackerbot challenges as noted.
|
||||
|
||||
---
|
||||
@@ -0,0 +1,171 @@
|
||||
<%
|
||||
require 'json'
|
||||
require 'securerandom'
|
||||
require 'digest/sha1'
|
||||
require 'fileutils'
|
||||
require 'erb'
|
||||
|
||||
if self.accounts.empty?
|
||||
abort('Sorry, you need to provide an account')
|
||||
end
|
||||
|
||||
$first_account = JSON.parse(self.accounts.first)
|
||||
$main_user = $first_account['username'].to_s
|
||||
$main_user_pass = $first_account['password'].to_s
|
||||
|
||||
# $second_account = JSON.parse(self.accounts[1])
|
||||
# $second_user = $second_account['username'].to_s
|
||||
# $second_password = $second_account['password'].to_s
|
||||
|
||||
# $third_account = JSON.parse(self.accounts[2])
|
||||
# $third_user = $third_account['username'].to_s
|
||||
# $third_password = $third_account['password'].to_s
|
||||
|
||||
# $fourth_account = JSON.parse(self.accounts[3])
|
||||
# $fourth_user = $third_account['username'].to_s
|
||||
# $fourth_password = $third_account['password'].to_s
|
||||
|
||||
# $server_ip = self.server_ip.first
|
||||
$root_password = self.root_password
|
||||
$flags = self.flags
|
||||
|
||||
REQUIRED_FLAGS = 2
|
||||
while $flags.length < REQUIRED_FLAGS
|
||||
$flags << "flag{#{SecureRandom.hex}}"
|
||||
Print.err "Warning: Not enough flags provided to hackerbot_config generator, some flags won't be tracked/marked!"
|
||||
end
|
||||
|
||||
def get_binding
|
||||
binding
|
||||
end
|
||||
-%>
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<hackerbot
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.github/cliffe/SecGen/hackerbot">
|
||||
<!--<hackerbot xmlns="http://www.github/cliffe/SecGen/hackerbotz"-->
|
||||
|
||||
<name>Hackerbot</name>
|
||||
|
||||
<AIML_chatbot_rules>config/AIML</AIML_chatbot_rules>
|
||||
|
||||
<!--Method for gaining shell access, can be overwritten per-attack-->
|
||||
<get_shell>sshpass -p <%= $root_password %> ssh -oStrictHostKeyChecking=no root@{{chat_ip_address}} /bin/bash</get_shell>
|
||||
|
||||
<messages>
|
||||
<show_attack_numbers />
|
||||
|
||||
<greeting>Hi there. Solve some challenges and I'll give you some flags.</greeting>
|
||||
|
||||
<!--Must provide alternatives for each message-->
|
||||
<say_ready>When you are ready, simply say 'ready'.</say_ready>
|
||||
<say_ready>'Ready'?</say_ready>
|
||||
<next>Ok, I'll do what I can to move things along...</next>
|
||||
<next>Moving things along to the next one...</next>
|
||||
<previous>Ok, I'll do what I can to back things up...</previous>
|
||||
<previous>Ok, backing up.</previous>
|
||||
<goto>Ok, skipping it along.</goto>
|
||||
<goto>Let me see what I can do to goto that attack.</goto>
|
||||
<last_attack>That was the last one for now. You can rest easy, until next time... (End.)</last_attack>
|
||||
<last_attack>That was the last one. Game over?</last_attack>
|
||||
<first_attack>You are back to the beginning!</first_attack>
|
||||
<first_attack>This is where it all began.</first_attack>
|
||||
<getting_shell>Doing my thing...</getting_shell>
|
||||
<getting_shell>Here we go...</getting_shell>
|
||||
<got_shell>...</got_shell>
|
||||
<got_shell>....</got_shell>
|
||||
<repeat>Let me know when you are 'ready', if you want to move on say 'next', or 'previous' and I'll move things along.</repeat>
|
||||
<repeat>Say 'ready', 'next', or 'previous'.</repeat>
|
||||
|
||||
<!--Single responses:-->
|
||||
<help>I am waiting for you to say 'ready', 'next', 'previous', 'list', 'goto *X*', or 'answer *X*'</help>
|
||||
<say_answer>Say "The answer is *X*".</say_answer>
|
||||
<no_quiz>There is no question to answer</no_quiz>
|
||||
<correct_answer>Correct</correct_answer>
|
||||
<incorrect_answer>Incorrect</incorrect_answer>
|
||||
<invalid>That's not possible.</invalid>
|
||||
<non_answer>Wouldn't you like to know.</non_answer>
|
||||
|
||||
<!--can be overwritten per-attack-->
|
||||
<shell_fail_message>Oh no. Failed to get shell... You need to let us in.</shell_fail_message>
|
||||
</messages>
|
||||
|
||||
<tutorial_info>
|
||||
<title>Mandatory Access Controls: AppArmor</title>
|
||||
<tutorial><%= ERB.new(File.read self.templates_path + 'intro.md.erb').result(self.get_binding) %></tutorial>
|
||||
<footer>
|
||||
<%= File.read self.templates_path + 'resources.md.erb' %>
|
||||
|
||||
<%= File.read self.templates_path + 'license.md.erb' %>
|
||||
|
||||
Randomised instance generated by [SecGen](http://github.com/cliffe/SecGen) (<%= Time.new.to_s %>)
|
||||
</footer>
|
||||
|
||||
<provide_tutorial>true</provide_tutorial>
|
||||
|
||||
</tutorial_info>
|
||||
|
||||
<attack>
|
||||
<%# $rand_secret = "secret#{SecureRandom.hex(3)}" %>
|
||||
<%# $rand_secret_file = "/home/#{$main_user}/secret#{SecureRandom.hex(3)}" %>
|
||||
<prompt>On your desktop system, use AppArmor to confine /usr/bin/tail so that it can read your ~/hello file but not your ~/mysecret file.</prompt>
|
||||
|
||||
<!-- <get_shell>sshpass -p <%= $root_password %> ssh -oStrictHostKeyChecking=no root@<%= $server_ip %> /bin/bash</get_shell> -->
|
||||
|
||||
<post_command>tail /home/<%= $main_user %>/hello; echo h-$?-; tail /home/<%= $main_user %>/mysecret; echo s-$?-; </post_command>
|
||||
|
||||
<condition>
|
||||
<output_matches>h-0-.*Permission denied.*s-[^0]*-</output_matches>
|
||||
<message>:) Well done! <%= $flags.pop %></message>
|
||||
<trigger_next_attack />
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>h-[^0]</output_matches>
|
||||
<message>:( Couldn't access the hello file. Update the profile rules to enable tail to read this file. If this is working for you, but not Hackerbot try adding "capability dac_override," to your profile.</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>s-0</output_matches>
|
||||
<message>:( Could access your mysecret file! Create/update an AppArmor profile that doesn't include access to this.</message>
|
||||
</condition>
|
||||
<else_condition>
|
||||
<message>:( Something was not right</message>
|
||||
</else_condition>
|
||||
|
||||
<tutorial>
|
||||
<%= ERB.new(File.read self.templates_path + 'mac_apparmor.md.erb').result(self.get_binding) %>
|
||||
</tutorial>
|
||||
</attack>
|
||||
|
||||
<!-- TODO: check file permissions to ensure they are using MAC -->
|
||||
<attack>
|
||||
<% $rand_port = rand(1025..65535).to_s %>
|
||||
<prompt>On your desktop system, use AppArmor to confine and start ncat (ncat -l -p <%= $rand_port %> -e /bin/bash -k) so that it can provide a shell that anyone who connects can run cat to read your ~/hello file but not your ~/mysecret file.</prompt>
|
||||
|
||||
<get_shell>nc {{chat_ip_address}} <%= $rand_port %></get_shell>
|
||||
|
||||
<post_command>cat /home/<%= $main_user %>/hello; echo h-$?-; cat /home/<%= $main_user %>/mysecret; echo s-$?-; </post_command>
|
||||
|
||||
<condition>
|
||||
<output_matches>h-0-.*s-[^0]*-</output_matches>
|
||||
<message>:) Well done! <%= $flags.pop %></message>
|
||||
<trigger_next_attack />
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>h-[^0]</output_matches>
|
||||
<message>:( Couldn't access the hello file. You should update the rules to let me connect and get access to the file. If this is working for you, but not Hackerbot try adding "capability dac_override," to your profile.</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>s-0</output_matches>
|
||||
<message>:( I managed to access your mysecret file! An AppArmor profile should be created to not include access to this.</message>
|
||||
</condition>
|
||||
<else_condition>
|
||||
<message>:( Something was not right</message>
|
||||
</else_condition>
|
||||
|
||||
<!-- <tutorial>< %= ERB.new(File.read self.templates_path + 'facls.md.erb').result(self.get_binding) %></tutorial> -->
|
||||
|
||||
</attack>
|
||||
|
||||
|
||||
</hackerbot>
|
||||
@@ -0,0 +1,114 @@
|
||||
<html>
|
||||
<head>
|
||||
<title><%= self.title %></title>
|
||||
</head>
|
||||
<body>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="css/github-markdown.css">
|
||||
<style>
|
||||
.markdown-body {
|
||||
box-sizing: border-box;
|
||||
min-width: 200px;
|
||||
max-width: 980px;
|
||||
margin: 0 auto;
|
||||
padding: 45px;
|
||||
}
|
||||
.markdown-body h4[id^='hackerbot']:after {
|
||||
display: inline-block;
|
||||
float: right;
|
||||
content: url("images/skullandusb.svg");
|
||||
width: 30px;
|
||||
}
|
||||
article {
|
||||
float: right;
|
||||
width: calc(100% - 300px);
|
||||
}
|
||||
.toc {
|
||||
float: left;
|
||||
font-size: smaller;
|
||||
color: #1a1d22;
|
||||
width: 300px;
|
||||
position: fixed;
|
||||
height: calc(100% - 56px);
|
||||
overflow-y: scroll;
|
||||
font-family: sans-serif;
|
||||
margin-top: 50px;
|
||||
}
|
||||
.toc ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin-left: 1em;
|
||||
}
|
||||
.toc li { /* Space between menu items*/
|
||||
margin: 1em 0;
|
||||
}
|
||||
.toc a {
|
||||
color: #1a1d22;
|
||||
text-decoration: none;
|
||||
}
|
||||
.toc a:hover {
|
||||
color: #6c036d;
|
||||
text-decoration: none;
|
||||
}
|
||||
.toc a:visited {
|
||||
color: #1a1d22;
|
||||
text-decoration: none;
|
||||
}
|
||||
.markdown-body pre, .markdown-body code {
|
||||
background-color: #570138;
|
||||
color: whitesmoke;
|
||||
}
|
||||
.markdown-body img[alt="small-left"] {
|
||||
max-width: 100px;
|
||||
float: left;
|
||||
}
|
||||
.markdown-body img[alt="small-right"] {
|
||||
max-width: 100px;
|
||||
float: right;
|
||||
}
|
||||
.markdown-body img[alt="tiny-right"] {
|
||||
max-width: 30px;
|
||||
float: right;
|
||||
}
|
||||
.markdown-body img[alt="small"] {
|
||||
max-width: 100px;
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding: 15px;
|
||||
}
|
||||
mark {
|
||||
background-color: white;
|
||||
color: #5b29bd;
|
||||
font-weight: bolder;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.markdown-body {
|
||||
padding: 15px;
|
||||
min-width: 200px;
|
||||
max-width: 980px;
|
||||
}
|
||||
.toc {
|
||||
float: none;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
height: auto;
|
||||
}
|
||||
article {
|
||||
float: none;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
<div class="toc">
|
||||
<%= self.html_TOC_rendered %>
|
||||
</div>
|
||||
|
||||
<article class="markdown-body">
|
||||
<%= self.html_rendered %>
|
||||
</article>
|
||||
<script src="js/code-prettify/loader/run_prettify.js?autoload=true&skin=sunburst&lang=css"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,6 @@
|
||||
## License
|
||||
This lab by [*Z. Cliffe Schreuders*](http://z.cliffe.schreuders.org) at Leeds Beckett University is licensed under a [*Creative Commons Attribution-ShareAlike 3.0 Unported License*](http://creativecommons.org/licenses/by-sa/3.0/deed.en_GB).
|
||||
|
||||
Included software source code is also licensed under the GNU General Public License, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||

|
||||
@@ -0,0 +1,228 @@
|
||||
## Mandatory Access Controls: Capabilities and AppArmor
|
||||
|
||||
Rule-based system-wide access controls can control what each application is authorised to do. The security system enforces exactly which files or resources are accessible to each process. They don't typically require applications to be launched into a sandbox, rules are applied to any applications that have policies.
|
||||
|
||||
## Capabilities: Coarse-grained rights
|
||||
|
||||
Some rule-based controls are quite coarsely grained. For example, Android grants permissions such as "Network", "SD Card", "Camera", and "GPS" access.
|
||||
|
||||
Another coarsely grained system is *Linux capabilities*, which break up root’s special permissions so that some programs can be granted specific "capabilities" rather than run as root. Normally on Unix, there are two types of users: privileged (uid=0) and unprivileged (uid != 0). The root user (0) is allowed to do practically anything and bypasses all kernel permission checks. Capabilities divide these privileges. Which makes it possible to, for example, allow a program to have raw network access or to call chroot (CAP\_CHROOT), without granting it all of root’s other privileges, such as the ability to access every file on the system.
|
||||
|
||||
See `man capabilities` for the full list of available capabilities.
|
||||
|
||||
One of the limitations of the traditional Unix approach to privilege is that programs that require special permissions, such as ping, need to run as root. In this case, it is so that ping can do raw network operations -- something normal users can't do. However, when ping runs as root (via setuid), then a programming mistake (vulnerability) in ping could possibly allow normal users root access.
|
||||
|
||||
Capabilities help to solve the problem. Instead of running the program setuid root, we can give it the capability to do what it needs without access to everything else that root is allowed to do.
|
||||
|
||||
Do the following to check whether ping is currently setuid:
|
||||
|
||||
```bash
|
||||
ls -la /bin/ping
|
||||
```
|
||||
`
|
||||
-rwsr-xr-x 1 root root 39992 Oct 25 2015 /usr/bin/ping
|
||||
`
|
||||
|
||||
Ping your own system (Ctrl-C to stop):
|
||||
|
||||
```bash
|
||||
ping localhost
|
||||
```
|
||||
|
||||
Now make a copy of ping:
|
||||
|
||||
```bash
|
||||
sudo cp /bin/ping /tmp/ping
|
||||
```
|
||||
|
||||
As your normal user (not root), try pinging again:
|
||||
|
||||
```bash
|
||||
/tmp/ping localhost
|
||||
```
|
||||
|
||||
It won’t work since it doesn't have the required permissions:
|
||||
|
||||
`
|
||||
ping: socket: Operation not permitted
|
||||
`
|
||||
|
||||
Check the man page of setcap:
|
||||
|
||||
```bash
|
||||
man setcap
|
||||
```
|
||||
|
||||
Now set ping to use the capability, by attaching the capability to the file:
|
||||
|
||||
```bash
|
||||
sudo setcap cap_net_raw=ep /tmp/ping
|
||||
```
|
||||
|
||||
Check that the program now has the capability, by running:
|
||||
|
||||
```bash
|
||||
sudo /sbin/getcap /tmp/ping
|
||||
```
|
||||
|
||||
You should now be able to use the /tmp/ping program as any user, and it will be able to ping as before:
|
||||
|
||||
```bash
|
||||
/tmp/ping localhost
|
||||
```
|
||||
|
||||
The advantage is that now the program cannot do all the other things root can do, so a vulnerability in ping wouldn't expose your entire system
|
||||
|
||||
==Log Book Question: Describe and demonstrate another example where capabilities can be used to remove the need for setuid.==
|
||||
|
||||
## AppArmor: Rule-based fine-grained controls
|
||||
|
||||
Another approach taken by some schemes is to simply specify a list of all the resources each application is authorised to access. This is the approach taken by AppArmor and TOMOYO, which are Linux Kernel security features.
|
||||
|
||||
First, check that AppArmor is installed and enabled on your Linux system:
|
||||
|
||||
```bash
|
||||
systemctl status apparmor
|
||||
|
||||
sudo aa-enabled
|
||||
```
|
||||
|
||||
AppArmor takes a rule-based approach to specify which files (and other permissions) a *program* gets access to. View the profiles that have been loaded:
|
||||
|
||||
```bash
|
||||
sudo aa-status
|
||||
```
|
||||
|
||||
The profiles are stored in /etc/apparmor.d/
|
||||
|
||||
View an example profile:
|
||||
|
||||
```bash
|
||||
less /etc/apparmor.d/bin.ping
|
||||
```
|
||||
|
||||
Note that the profile has rules to enable networking (by allowing the program to use any matching capabilities it has been assigned, and permitting it to use networking):
|
||||
|
||||
```
|
||||
capability net_raw,
|
||||
|
||||
capability setuid,
|
||||
|
||||
network inet raw,
|
||||
|
||||
network inet6 raw,
|
||||
|
||||
```
|
||||
|
||||
Some rules grant access to files. This permits the `/etc/modules.conf` file to be read:
|
||||
|
||||
```
|
||||
/etc/modules.conf r,
|
||||
```
|
||||
|
||||
And this permits the program to read "r", memory map "m", and execute the ping program itself:
|
||||
|
||||
```
|
||||
/{,usr/}bin/ping mixr,
|
||||
```
|
||||
|
||||
Note that when a process (running program) starts a new process (program on disk), there are a few options about how the new process can be confined. The option used here is Inherit, "ix", which means that the new process is confined by this same profile. This is generally the safest and easiest to understand. Other options include using its own separate profile or a child sub-profile.
|
||||
|
||||
There are also some time-saving *abstractions* included, which are collections of rules:
|
||||
|
||||
```
|
||||
#include \<abstractions/base>
|
||||
```
|
||||
|
||||
Have a look at a more complicated profile:
|
||||
|
||||
```bash
|
||||
less /etc/apparmor.d/usr.sbin.tcpdump
|
||||
```
|
||||
|
||||
Creating your own AppArmor profile
|
||||
----------------------------------
|
||||
|
||||
You will start by using AppArmor to confine a harmless text viewer to enable it to read \~/hello, but not allow it to read \~/mysecret.
|
||||
|
||||
Create a barebones profile for less by running
|
||||
|
||||
```bash
|
||||
sudo aa-autodep /bin/less
|
||||
```
|
||||
|
||||
Note that your profile is now in complain mode:
|
||||
|
||||
```bash
|
||||
sudo aa-status
|
||||
```
|
||||
|
||||
Set the new profile to enforcing:
|
||||
|
||||
```bash
|
||||
sudo aa-enforce /bin/less
|
||||
```
|
||||
|
||||
Test that you can no longer open either of your files.
|
||||
|
||||
```bash
|
||||
less hello
|
||||
|
||||
less mysecret
|
||||
```
|
||||
|
||||
And with root:
|
||||
|
||||
```bash
|
||||
sudo less hello
|
||||
```
|
||||
|
||||
View your new profile:
|
||||
|
||||
```bash
|
||||
less /etc/apparmor.d/bin.less
|
||||
```
|
||||
|
||||
View the audit log, which includes the AppArmor denials that have taken place:
|
||||
|
||||
```bash
|
||||
sudo less /var/log/audit/audit.log
|
||||
```
|
||||
|
||||
Note that your profile is now in enforcing mode:
|
||||
|
||||
```bash
|
||||
sudo aa-status
|
||||
```
|
||||
|
||||
Change your profile into complain mode so that the denials are logged but not enforced.
|
||||
|
||||
```bash
|
||||
sudo aa-complain /bin/less
|
||||
```
|
||||
|
||||
AppArmor has a learning mode to make rule construction easier. During learning mode, AppArmor logs all the denials (either in enforcing more or complaining mode) then when you are ready it steps you through each of the things the program did, with the option to add to the profile rules.
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
sudo aa-genprof /bin/less
|
||||
```
|
||||
|
||||
Leave that running and (in a separate console) run less to view some files.
|
||||
|
||||
When you are finished, go back to your running aa-genprof and press "S" to scan the audit log for rules.
|
||||
|
||||
The aa-genprof will ask you whether to add various rules to your profile. You should choose to accept all the access attempts that you deem appropriate (most of them, hopefully!). If you opened your mysecret file, you should not add that to the rules.
|
||||
|
||||
Note that you can "deny" access to a file, but you can also choose to "ignore" those files, because anything not explicitly granted by the AppArmor profile will be denied.
|
||||
|
||||
Change your profile into enforce mode so that the denials are enforced.
|
||||
|
||||
```bash
|
||||
sudo aa-enforce /bin/less
|
||||
```
|
||||
|
||||
Update and test to create a profile that enables less to access hello, and any files in your Documents folder, while denying access to your mysecret file.
|
||||
|
||||
==Log Book Question: What are the advantages and disadvantages of using a blacklist (deny) vs whitelist (ignore) approach to writing AppArmor rules?==
|
||||
@@ -0,0 +1,5 @@
|
||||
# Resources
|
||||
This excellent paper describes Linux ACL in detail:
|
||||
|
||||
[^1]: Grünbacher, Andreas. "POSIX Access Control Lists on Linux." *USENIX Annual Technical Conference*, FREENIX Track. 2003.
|
||||
<https://www.usenix.org/legacy/events/usenix03/tech/freenix03/full_papers/gruenbacher/gruenbacher.pdf>
|
||||
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/ruby
|
||||
require_relative '../../../../../../lib/objects/local_hackerbot_config_generator.rb'
|
||||
|
||||
class HB < HackerbotConfigGenerator
|
||||
|
||||
attr_accessor :server_ip
|
||||
|
||||
def initialize
|
||||
super
|
||||
self.module_name = 'Hackerbot Config Generator Authentication'
|
||||
self.title = 'Assignment Security Spec'
|
||||
|
||||
self.local_dir = File.expand_path('../../',__FILE__)
|
||||
self.templates_path = "#{self.local_dir}/templates/"
|
||||
self.config_template_path = "#{self.local_dir}/templates/lab.xml.erb"
|
||||
self.html_template_path = "#{self.local_dir}/templates/labsheet.html.erb"
|
||||
|
||||
self.server_ip = []
|
||||
end
|
||||
|
||||
def get_options_array
|
||||
super + [['--server_ip', GetoptLong::REQUIRED_ARGUMENT]]
|
||||
end
|
||||
|
||||
def process_options(opt, arg)
|
||||
super
|
||||
case opt
|
||||
when '--server_ip'
|
||||
self.server_ip << arg;
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
HB.new.run
|
||||
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<generator xmlns="http://www.github/cliffe/SecGen/generator"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.github/cliffe/SecGen/generator">
|
||||
<name>Hackerbot config for an access control lab</name>
|
||||
<author>Z. Cliffe Schreuders</author>
|
||||
<module_license>GPLv3</module_license>
|
||||
<description>Generates a config file for a hackerbot for an integrity lab.
|
||||
Topics covered: .</description>
|
||||
|
||||
<type>hackerbot_config</type>
|
||||
<platform>linux</platform>
|
||||
|
||||
<read_fact>accounts</read_fact>
|
||||
<read_fact>flags</read_fact>
|
||||
<read_fact>root_password</read_fact>
|
||||
|
||||
<!--TODO: require input, such as accounts, or fail?-->
|
||||
|
||||
<default_input into="accounts">
|
||||
<generator type="account">
|
||||
<input into="username">
|
||||
<value>vagrant</value>
|
||||
</input>
|
||||
</generator>
|
||||
</default_input>
|
||||
|
||||
<default_input into="flags">
|
||||
<!-- <generator type="flag_generator"/>
|
||||
<generator type="flag_generator"/> -->
|
||||
</default_input>
|
||||
|
||||
<default_input into="root_password">
|
||||
<value>puppet</value>
|
||||
</default_input>
|
||||
|
||||
<output_type>hackerbot</output_type>
|
||||
|
||||
</generator>
|
||||
@@ -0,0 +1,29 @@
|
||||
<html>
|
||||
<head>
|
||||
<title><%= self.title %></title>
|
||||
</head>
|
||||
<body>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="css/github-markdown.css">
|
||||
<style>
|
||||
.markdown-body {
|
||||
box-sizing: border-box;
|
||||
min-width: 200px;
|
||||
max-width: 980px;
|
||||
margin: 0 auto;
|
||||
padding: 45px;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.markdown-body {
|
||||
padding: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<article class="markdown-body">
|
||||
|
||||
<%= self.html_rendered %>
|
||||
|
||||
</article>
|
||||
<script src="js/code-prettify/loader/run_prettify.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,4 @@
|
||||
## License
|
||||
This lab by [*Z. Cliffe Schreuders*](http://z.cliffe.schreuders.org) at Leeds Beckett University is licensed under a [*Creative Commons Attribution-ShareAlike 3.0 Unported License*](http://creativecommons.org/licenses/by-sa/3.0/deed.en_GB).
|
||||
|
||||
Included software source code is also licensed under the GNU General Public License, either version 3 of the License, or (at your option) any later version.
|
||||
@@ -0,0 +1,101 @@
|
||||
## Assignment description
|
||||
|
||||
Your task is to design and implement technical security defenses, to achieve the required functionality as specified below in this requirements specification, and you will describe your approach in a technical report (which is decribed in the module handbook).
|
||||
|
||||
You need to make your actual system configuration changes to the VMs provided.
|
||||
|
||||
The systems you are provided includes insecure settings and/or software.
|
||||
|
||||
Your report's contents should follow the structure of the below headings (plus Executive Summary, Limitations, Conclusion, and References sections) to describe the changes you make, including describing any insecure settings or software you find and fix in the systems you have been provided. Describe every change that was necessary, with screenshots showing the changes and demonstrating whether the security functions as intended.
|
||||
|
||||
## Users
|
||||
username: user1
|
||||
password: password1
|
||||
Metadata: room number 1
|
||||
Phone extension: 2342
|
||||
group: admin
|
||||
|
||||
username: user2
|
||||
password: password2
|
||||
Metadata: room number 2
|
||||
Phone extension: 2343
|
||||
group: staff
|
||||
|
||||
username: user3
|
||||
password: password3
|
||||
Metadata: room number 3
|
||||
Phone extension: 2344
|
||||
group: staff
|
||||
|
||||
username: user4
|
||||
password: password4
|
||||
Metadata: room number 3
|
||||
Phone extension: 2344
|
||||
group: staff,developer
|
||||
|
||||
username: user5
|
||||
password: password5
|
||||
Metadata: room number 4
|
||||
Phone extension: 2344
|
||||
group: staff,developer
|
||||
|
||||
### Authentication
|
||||
You need to use **authentication schemes of your choice** to enable these Users to log into systems and services. Justify your approach and describe how well it achieves the security requirements documented below.
|
||||
|
||||
In your report describe what it would take for a new user to be added, or for a user to change their password. Describe the affect of network eavesdropping on the authentication.
|
||||
|
||||
**SSH settings:** Disable SSH access for user1, user2, user3, user4, and user5, on the server and desktop VMs. This change is important to make as soon as you add these users to your VMs. Leave the SSH access settings otherwise unchanged; for example, <%= $main_user %> should be able to SSH to these VMs. (When marking your work we may SSH to your VMs).
|
||||
|
||||
## Systems
|
||||
You are provided with VMs, which you are required to configure, and leave in a state for review, with persistent settings that survive reboot.
|
||||
|
||||
**To install software:** For temporary access to the Internet, run `sudo dhclient ens3` so you can install additional software via `apt-get` as required. Then run `sudo service networking restart` to reset your IP address which will restore network connectivity between your other VMs.
|
||||
|
||||
### server
|
||||
**Web server**
|
||||
The server VM needs to be running an Apache web server, hosting a website.
|
||||
|
||||
**FTP server**
|
||||
An FTP server needs to be running, accepting connections from any of the Users, with their credentials. Users should have their own directory for saving backups, which should not be available to other users. A shared directory should be avaiable to all authenticated users. A "code" directory should only be available to users in the "developers" group.
|
||||
|
||||
**SMB server**
|
||||
A centralised Windows file share (Samba) should be hosted on this VM and available to all Users with their credentials.
|
||||
|
||||
**Identified security problems**
|
||||
In your report describe any insecure settings and/or software you found on the server and document how you made the server secure.
|
||||
|
||||
**Security controls**
|
||||
The server system should be locked down, in a way that limits the potential damage caused by a vulnerability in the file sharing services or the webserver (Hint: consider sandboxing, containerisation, and/or MAC restrictions). In your report make it clear how much protection there is against malicious users, or software vulnerabilities.
|
||||
|
||||
All network services should be configured to provide secure communication. In your report describe the information an eavesdropper could capture from the network.
|
||||
|
||||
Use network-based authentication to enable Users to access the services using their credentials. Only the Admin user (user1 above, a member of the admin group) should be able to log directly into the server. In your report describe what it would take for a new user to be granted access, or for a user to change their password.
|
||||
|
||||
### developer_desktop
|
||||
**Authentication**
|
||||
The developer_desktop system should be available for anyone in the developer or admin group to login. They should have superuser/sudo access. Use network-based authentication.
|
||||
|
||||
**Functionality**
|
||||
The developers need to be able to compile C code, and access the network shares.
|
||||
|
||||
**Identified security problems**
|
||||
In your report describe any insecure settings and/or software you found and document how you made the system secure.
|
||||
|
||||
### staff_desktop
|
||||
**Authentication**
|
||||
This staff_desktop system should be available for any valid User to login. They should not have superuser access. Only users in the admin group should have superuser access. Use network-based authentication.
|
||||
|
||||
**Access controls**
|
||||
New files created by users should not be automatically shared with other users on the system. There should be a shared directory "/srv/shared" for users to share files locally.
|
||||
|
||||
**Directory service**
|
||||
Users should have some way to query phone numbers and room numbers of any Users. Users should also be able to use Firefox to access the website on the server; and have access to the FTP and Samba server via Dolphin.
|
||||
|
||||
**Security controls**
|
||||
Lock down the system to limit damage that could be caused by vulnerabilities. In your report make it clear how much protection there is against malicious users, or software vulnerabilities.
|
||||
|
||||
**Identified security problems**
|
||||
In your report describe any insecure settings and/or software you found and document how you made the system secure.
|
||||
|
||||
### auth_server
|
||||
This server is intended to be used to host network-authentication, such as LDAP, Kerberos, and/or Active Directory (such as via Samba DC). If you wish to create a Windows VM to act as a domain controller, that may also be possible via oVirt. In that case, visit <aet-ovirt.aet.leedsbeckett.ac.uk> and create a VM on the Internal network); login with your student id, create a VM, and configure the networking. It will be your own responsibility to figure out how to get the networking correct and you need to make sure that any external oVirt VMs are kept running so that when we test your VMs the authentication works.
|
||||
@@ -0,0 +1,9 @@
|
||||
# Assignment Security Specifications
|
||||
|
||||
## Your login details for the VMs
|
||||
User: <%= $main_user %>
|
||||
Password: tiaspbiqe2r (**t**his **i**s **a** **s**ecure **p**assword **b**ut **i**s **q**uite **e**asy **2** **r**emember)
|
||||
|
||||
You can sudo with <%= $main_user %>, in order to configure the systems.
|
||||
|
||||
You don't need to login to the sec_spec_server, it just hosts this document.
|
||||
@@ -0,0 +1,106 @@
|
||||
<%
|
||||
require 'json'
|
||||
require 'securerandom'
|
||||
require 'digest/sha1'
|
||||
require 'fileutils'
|
||||
require 'erb'
|
||||
|
||||
if self.accounts.empty?
|
||||
abort('Sorry, you need to provide an account')
|
||||
end
|
||||
|
||||
$first_account = JSON.parse(self.accounts.first)
|
||||
$main_user = $first_account['username'].to_s
|
||||
$main_user_pass = $first_account['password'].to_s
|
||||
|
||||
|
||||
$server_ip = self.server_ip.first
|
||||
$root_password = self.root_password
|
||||
$flags = self.flags
|
||||
|
||||
REQUIRED_FLAGS = 0
|
||||
while $flags.length < REQUIRED_FLAGS
|
||||
$flags << "flag{#{SecureRandom.hex}}"
|
||||
Print.err "Warning: Not enough flags provided to hackerbot_config generator, some flags won't be tracked/marked!"
|
||||
end
|
||||
|
||||
def get_binding
|
||||
binding
|
||||
end
|
||||
-%>
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<hackerbot
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.github/cliffe/SecGen/hackerbot">
|
||||
<!--<hackerbot xmlns="http://www.github/cliffe/SecGen/hackerbotz"-->
|
||||
|
||||
<name>Markerbot</name>
|
||||
|
||||
<AIML_chatbot_rules>config/AIML</AIML_chatbot_rules>
|
||||
|
||||
<!--Method for gaining shell access, can be overwritten per-attack-->
|
||||
<get_shell>sshpass -p <%= $root_password %> ssh -oStrictHostKeyChecking=no root@{{chat_ip_address}} /bin/bash</get_shell>
|
||||
|
||||
<messages>
|
||||
<show_attack_numbers />
|
||||
|
||||
<greeting>Hi there. Solve some challenges and I'll give you some flags.</greeting>
|
||||
|
||||
<!--Must provide alternatives for each message-->
|
||||
<say_ready>When you are ready, simply say 'ready'.</say_ready>
|
||||
<say_ready>'Ready'?</say_ready>
|
||||
<next>Ok, I'll do what I can to move things along...</next>
|
||||
<next>Moving things along to the next one...</next>
|
||||
<previous>Ok, I'll do what I can to back things up...</previous>
|
||||
<previous>Ok, backing up.</previous>
|
||||
<goto>Ok, skipping it along.</goto>
|
||||
<goto>Let me see what I can do to goto that attack.</goto>
|
||||
<last_attack>That was the last one for now. You can rest easy, until next time... (End.)</last_attack>
|
||||
<last_attack>That was the last one. Game over?</last_attack>
|
||||
<first_attack>You are back to the beginning!</first_attack>
|
||||
<first_attack>This is where it all began.</first_attack>
|
||||
<getting_shell>Doing my thing...</getting_shell>
|
||||
<getting_shell>Here we go...</getting_shell>
|
||||
<got_shell>...</got_shell>
|
||||
<got_shell>....</got_shell>
|
||||
<repeat>Let me know when you are 'ready', if you want to move on say 'next', or 'previous' and I'll move things along.</repeat>
|
||||
<repeat>Say 'ready', 'next', or 'previous'.</repeat>
|
||||
|
||||
<!--Single responses:-->
|
||||
<help>I am waiting for you to say 'ready', 'next', 'previous', 'list', 'goto *X*', or 'answer *X*'</help>
|
||||
<say_answer>Say "The answer is *X*".</say_answer>
|
||||
<no_quiz>There is no question to answer</no_quiz>
|
||||
<correct_answer>Correct</correct_answer>
|
||||
<incorrect_answer>Incorrect</incorrect_answer>
|
||||
<invalid>That's not possible.</invalid>
|
||||
<non_answer>Wouldn't you like to know.</non_answer>
|
||||
|
||||
<!--can be overwritten per-attack-->
|
||||
<shell_fail_message>Oh no. Failed to get shell... You need to let us in.</shell_fail_message>
|
||||
</messages>
|
||||
|
||||
<tutorial_info>
|
||||
<title>Assignment Spec</title>
|
||||
<tutorial>
|
||||
<%= ERB.new(File.read self.templates_path + 'intro.md.erb').result(self.get_binding) %>
|
||||
<%= ERB.new(File.read self.templates_path + 'assignment_spec.md.erb').result(self.get_binding) %>
|
||||
</tutorial>
|
||||
<footer>
|
||||
Randomised instance generated by [SecGen](http://github.com/cliffe/SecGen) (<%= Time.new.to_s %>)
|
||||
</footer>
|
||||
|
||||
<provide_tutorial>true</provide_tutorial>
|
||||
|
||||
</tutorial_info>
|
||||
|
||||
<attack>
|
||||
<prompt>Nothing to see here...</prompt>
|
||||
|
||||
<tutorial>
|
||||
</tutorial>
|
||||
|
||||
</attack>
|
||||
|
||||
|
||||
</hackerbot>
|
||||
@@ -0,0 +1,114 @@
|
||||
<html>
|
||||
<head>
|
||||
<title><%= self.title %></title>
|
||||
</head>
|
||||
<body>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="css/github-markdown.css">
|
||||
<style>
|
||||
.markdown-body {
|
||||
box-sizing: border-box;
|
||||
min-width: 200px;
|
||||
max-width: 980px;
|
||||
margin: 0 auto;
|
||||
padding: 45px;
|
||||
}
|
||||
.markdown-body h4[id^='hackerbot']:after {
|
||||
display: inline-block;
|
||||
float: right;
|
||||
content: url("images/skullandusb.svg");
|
||||
width: 30px;
|
||||
}
|
||||
article {
|
||||
float: right;
|
||||
width: calc(100% - 300px);
|
||||
}
|
||||
.toc {
|
||||
float: left;
|
||||
font-size: smaller;
|
||||
color: #1a1d22;
|
||||
width: 300px;
|
||||
position: fixed;
|
||||
height: calc(100% - 56px);
|
||||
overflow-y: scroll;
|
||||
font-family: sans-serif;
|
||||
margin-top: 50px;
|
||||
}
|
||||
.toc ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin-left: 1em;
|
||||
}
|
||||
.toc li { /* Space between menu items*/
|
||||
margin: 1em 0;
|
||||
}
|
||||
.toc a {
|
||||
color: #1a1d22;
|
||||
text-decoration: none;
|
||||
}
|
||||
.toc a:hover {
|
||||
color: #6c036d;
|
||||
text-decoration: none;
|
||||
}
|
||||
.toc a:visited {
|
||||
color: #1a1d22;
|
||||
text-decoration: none;
|
||||
}
|
||||
.markdown-body pre, .markdown-body code {
|
||||
background-color: #570138;
|
||||
color: whitesmoke;
|
||||
}
|
||||
.markdown-body img[alt="small-left"] {
|
||||
max-width: 100px;
|
||||
float: left;
|
||||
}
|
||||
.markdown-body img[alt="small-right"] {
|
||||
max-width: 100px;
|
||||
float: right;
|
||||
}
|
||||
.markdown-body img[alt="tiny-right"] {
|
||||
max-width: 30px;
|
||||
float: right;
|
||||
}
|
||||
.markdown-body img[alt="small"] {
|
||||
max-width: 100px;
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding: 15px;
|
||||
}
|
||||
mark {
|
||||
background-color: white;
|
||||
color: #5b29bd;
|
||||
font-weight: bolder;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.markdown-body {
|
||||
padding: 15px;
|
||||
min-width: 200px;
|
||||
max-width: 980px;
|
||||
}
|
||||
.toc {
|
||||
float: none;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
height: auto;
|
||||
}
|
||||
article {
|
||||
float: none;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
<div class="toc">
|
||||
<%= self.html_TOC_rendered %>
|
||||
</div>
|
||||
|
||||
<article class="markdown-body">
|
||||
<%= self.html_rendered %>
|
||||
</article>
|
||||
<script src="js/code-prettify/loader/run_prettify.js?autoload=true&skin=sunburst&lang=css"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/ruby
|
||||
require_relative '../../../../../../lib/objects/local_hackerbot_config_generator.rb'
|
||||
|
||||
class HB < HackerbotConfigGenerator
|
||||
|
||||
attr_accessor :server_ip
|
||||
|
||||
def initialize
|
||||
super
|
||||
self.module_name = 'Hackerbot Config Generator'
|
||||
self.title = 'Lab'
|
||||
|
||||
self.local_dir = File.expand_path('../../',__FILE__)
|
||||
self.templates_path = "#{self.local_dir}/templates/"
|
||||
self.config_template_path = "#{self.local_dir}/templates/lab.xml.erb"
|
||||
self.html_template_path = "#{self.local_dir}/templates/labsheet.html.erb"
|
||||
|
||||
self.server_ip = []
|
||||
end
|
||||
|
||||
def get_options_array
|
||||
super + [['--server_ip', GetoptLong::REQUIRED_ARGUMENT]]
|
||||
end
|
||||
|
||||
def process_options(opt, arg)
|
||||
super
|
||||
case opt
|
||||
when '--server_ip'
|
||||
self.server_ip << arg;
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
HB.new.run
|
||||
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<generator xmlns="http://www.github/cliffe/SecGen/generator"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.github/cliffe/SecGen/generator">
|
||||
<name>Hackerbot config for an access control lab</name>
|
||||
<author>Z. Cliffe Schreuders</author>
|
||||
<module_license>GPLv3</module_license>
|
||||
<description>Generates a config file for a hackerbot for an integrity lab.
|
||||
Topics covered: .</description>
|
||||
|
||||
<type>hackerbot_config</type>
|
||||
<platform>linux</platform>
|
||||
|
||||
<read_fact>accounts</read_fact>
|
||||
<read_fact>flags</read_fact>
|
||||
<read_fact>root_password</read_fact>
|
||||
|
||||
<!--TODO: require input, such as accounts, or fail?-->
|
||||
|
||||
<default_input into="accounts">
|
||||
<generator type="account">
|
||||
<input into="username">
|
||||
<value>vagrant</value>
|
||||
</input>
|
||||
</generator>
|
||||
</default_input>
|
||||
|
||||
<default_input into="flags">
|
||||
<!-- <generator type="flag_generator"/> -->
|
||||
</default_input>
|
||||
|
||||
<default_input into="root_password">
|
||||
<value>puppet</value>
|
||||
</default_input>
|
||||
|
||||
<output_type>hackerbot</output_type>
|
||||
|
||||
</generator>
|
||||
@@ -0,0 +1,29 @@
|
||||
<html>
|
||||
<head>
|
||||
<title><%= self.title %></title>
|
||||
</head>
|
||||
<body>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="css/github-markdown.css">
|
||||
<style>
|
||||
.markdown-body {
|
||||
box-sizing: border-box;
|
||||
min-width: 200px;
|
||||
max-width: 980px;
|
||||
margin: 0 auto;
|
||||
padding: 45px;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.markdown-body {
|
||||
padding: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<article class="markdown-body">
|
||||
|
||||
<%= self.html_rendered %>
|
||||
|
||||
</article>
|
||||
<script src="js/code-prettify/loader/run_prettify.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,4 @@
|
||||
## License
|
||||
This lab by [*Z. Cliffe Schreuders*](http://z.cliffe.schreuders.org) at Leeds Beckett University is licensed under a [*Creative Commons Attribution-ShareAlike 3.0 Unported License*](http://creativecommons.org/licenses/by-sa/3.0/deed.en_GB).
|
||||
|
||||
Included software source code is also licensed under the GNU General Public License, either version 3 of the License, or (at your option) any later version.
|
||||
@@ -0,0 +1,274 @@
|
||||
## Introduction to Sandboxing and Isolation
|
||||
|
||||
There are many reasons for not trusting software: the authors may have been designed the software to act maliciously (malware) or they may have made some design or implementation mistakes that make the software vulnerable to attack. This is where access controls come in. Access controls restrict what each *subject* on a system is authorised to do. Traditionally access controls (such as Unix file permissions, which are user-oriented) have focussed on restricting what each user on a system can do. However, over time this has proven to be insufficient since this means that every program on a system is trusted with all of a user's authorisation: any program can read or delete all of a user's personal documents, Web history, and so on.
|
||||
|
||||
*Sandboxing* (or application-oriented access controls) involves restricting what a program or group of programs can do. This can significantly improve the security of a system since a rogue program can do far less damage to the system if it is restricted to only the permissions it requires to function correctly.
|
||||
|
||||
One approach to sandboxing is to run applications in isolated environments, with only access to resources (such as files) that are accessible from within the sandbox.
|
||||
|
||||
## Container-based sandboxes and chroot
|
||||
|
||||
Container-based sandboxes share the kernel but have separate user-space resources. This is more efficient than system-level virtualisation. For example, chroot() is a system call on Unix systems, that changes the root directory for a process and its children. The new namespace of the application limits it to only access files inside the specified directory tree. A wrapper program "chroot" can be used to launch programs into a "chroot jail". Only root can perform a chroot but should change identity asap because root can also escape a chroot jail (by performing another `chroot()`), so no program in a chroot should ever stay as root.
|
||||
|
||||
There are resources such as process controls and networking that are not mediated. Other mechanisms solve some of these problems, such as FreeBSD Jails.
|
||||
|
||||
You will create a chroot environment (a directory containing all the files that the "sandboxed" programs require), and run some programs inside it:...
|
||||
|
||||
**On your desktop system**:
|
||||
|
||||
Create a directory:
|
||||
|
||||
```bash
|
||||
sudo mkdir /opt/chrootdir
|
||||
```
|
||||
|
||||
Copy everything needed to run ls (LS) inside a chroot into a directory
|
||||
|
||||
First, we should look at the details of the ls executable:
|
||||
|
||||
```bash
|
||||
ls -la /bin/ls
|
||||
```
|
||||
`
|
||||
-rwxr-xr-x 1 root root 130736 Feb 22 2017 /bin/ls
|
||||
`
|
||||
|
||||
These details show that the file in /bin/ls is not a symbolic link.
|
||||
|
||||
Now try running the ldd command on ls:
|
||||
|
||||
```bash
|
||||
ldd /bin/ls
|
||||
```
|
||||
|
||||
You should get a result that looks something like this:
|
||||
|
||||
```bash
|
||||
linux-vdso.so.1 (0x00007ffcfe2cf000)
|
||||
|
||||
libselinux.so.1 > /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f954890d000)
|
||||
|
||||
libc.so.6 > /lib/x86_64-linux-gnu/libc.so.6 (0x00007f954856e000)
|
||||
|
||||
libpcre.so.3 > /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007f95482fb000)
|
||||
|
||||
libdl.so.2 > /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f95480f7000)
|
||||
|
||||
/lib64/ld-linux-x86-64.so.2 (0x00007f9548d56000)
|
||||
|
||||
libpthread.so.0 > /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f9547eda000)
|
||||
```
|
||||
|
||||
If you are patient you could copy each required file into your chroot directory. Otherwise, as you can see, all the files can be found in /lib/ and /lib64/.
|
||||
|
||||
Try the following (copy all the /lib/ files into the cage):
|
||||
|
||||
```bash
|
||||
sudo rsync -av /lib* /opt/chrootdir/
|
||||
```
|
||||
|
||||
Finally, copy ls.
|
||||
|
||||
```bash
|
||||
sudo rsync -av /bin/ls /opt/chrootdir/bin/
|
||||
```
|
||||
|
||||
Run ls in a chroot:
|
||||
|
||||
```bash
|
||||
sudo chroot /opt/chrootdir/ /bin/ls
|
||||
```
|
||||
|
||||
Note that ls can only see the files that are in the chroot cage.
|
||||
|
||||
Run ls in the chroot, and attempt to view the root (/) directory:
|
||||
|
||||
```bash
|
||||
sudo chroot /opt/chrootdir/ /bin/ls /
|
||||
```
|
||||
|
||||
Note that again, as far as anything in the chrooted program is concerned, what the rest of the system calls "/opt/chrootdir/", it sees as "/". This is referred to as the program's *namespace*.
|
||||
|
||||
Create a more complete chroot environment, for running command line programs, including bash (the Linux shell command prompt).
|
||||
|
||||
```bash
|
||||
sudo rsync -av /bin/ /opt/chrootdir/bin/
|
||||
|
||||
sudo rsync -av /etc/ /opt/chrootdir/etc/
|
||||
|
||||
sudo rsync -av /usr/ /opt/chrootdir/usr/
|
||||
|
||||
sudo mkdir /opt/chrootdir/home/
|
||||
```
|
||||
|
||||
This will take a fair while. You can continue the exercise in another bash window/tab, or read about [*bind mounting*](http://docs.1h.com/Bind_mounts) while you wait.
|
||||
|
||||
Once the install is complete, bind mount /sys, /dev, and /proc into the cage:
|
||||
|
||||
```bash
|
||||
sudo mkdir /opt/chrootdir/dev /opt/chrootdir/sys /opt/chrootdir/proc
|
||||
|
||||
sudo mount --bind /dev /opt/chrootdir/dev
|
||||
sudo mount --bind /sys /opt/chrootdir/sys
|
||||
sudo mount --bind /proc /opt/chrootdir/proc
|
||||
```
|
||||
|
||||
Read `man mount` to see what this does, and understand the security consequences.
|
||||
|
||||
==Lab Book Question: Why might it not be a good idea to bind mount the entire root "/" directory into the chroot cage?==
|
||||
|
||||
Now run bash inside the chroot:
|
||||
|
||||
```bash
|
||||
sudo chroot /opt/chrootdir /bin/bash
|
||||
```
|
||||
|
||||
Create a new user within the chroot (you will be prompted to enter a password for the new user):
|
||||
|
||||
```bash
|
||||
sudo useradd -d /home/username username; sudo passwd username
|
||||
```
|
||||
|
||||
Then to make bash switch to this new user::
|
||||
|
||||
```bash
|
||||
su - username
|
||||
```
|
||||
|
||||
Note that you can now run commands and (mostly) only affect the chroot directory.
|
||||
|
||||
Experiment with what is possible from within the chroot cage. You may wish to copy across further files and their dependencies from the main system to run from inside the chroot.
|
||||
|
||||
> Tips: to share the same X server (so you can run graphical program from the chroot, run "export DISPLAY=:0".
|
||||
|
||||
What can you see in /, /opt, /proc?
|
||||
|
||||
==Lab Book Question: Can you access anything outside of the chroot? As a normal user? As root?==
|
||||
|
||||
Understand that you can still access the network and possibly do damage via the bind mounted directories.
|
||||
|
||||
In general, we would typically create a minimal install for a chroot environment, such as [*https://wiki.debian.org/Debootstrap*](https://wiki.debian.org/Debootstrap)
|
||||
|
||||
## Docker
|
||||
|
||||
Docker builds on chroot, and additional virtualisation features to automate the creation and deployment of containerised OS's and applications. Docker improves security compared to chroot, using LXC (and others, such as libcontainer) to provide added isolation by making use of Linux kernel cgroups to limit resources such as CPU, memory, block I/O, network. Compared to chroot Docker provides some additional protection against root users escaping confinement.
|
||||
|
||||
Docker is portable across Linux systems, and makes use of reusable base images, and automated approaches for automating building containers to specifications.
|
||||
|
||||
Docker *images* are reusable bases that can be used to create *containers*, and can be downloaded via the docker command, and can be browsed online at Docker Hub: [*https://hub.docker.com/*](https://hub.docker.com/)
|
||||
|
||||
If you had an Internet connection you could run a command such as `docker pull ubuntu` to download an image based on Ubuntu Linux.
|
||||
|
||||
We have prepared an isolated environment for you, with some bases already downloaded for you to use.
|
||||
|
||||
View the bases available:
|
||||
|
||||
```bash
|
||||
sudo docker images
|
||||
```
|
||||
|
||||
The bases available to you already includes busybox, ubuntu:xenial, and debian:stretch. Busybox is a very minimal Linux system popular on embedded devices; Ubuntu and Debian are *complete distributions of Linux*; these bases provide a minimal installation of these distros, but into these containers, you could install pretty much any Ubuntu/Debian packages within.
|
||||
|
||||
Create a container and launch a command into a container:
|
||||
|
||||
```bash
|
||||
sudo docker run busybox echo "hello this is busybox"
|
||||
|
||||
sudo docker run busybox echo "busybox!"
|
||||
```
|
||||
|
||||
And run:
|
||||
|
||||
```bash
|
||||
sudo docker run debian:stretch echo "debian!"
|
||||
```
|
||||
|
||||
Each of the above commands created and then runs a command in a new container based on images. Note the amazing speed to create new containers compared to manual creation for chroot, or how long it can take to create full VMs.
|
||||
|
||||
View a list of all the Docker containers on your system:
|
||||
|
||||
```bash
|
||||
sudo docker ps -a
|
||||
```
|
||||
|
||||
Run an interactive command-line:
|
||||
|
||||
```bash
|
||||
sudo docker run -it busybox sh
|
||||
```
|
||||
> Press Ctrl-D to exit.
|
||||
|
||||
Run an interactive Ubuntu command-line:
|
||||
|
||||
```bash
|
||||
sudo docker run -it ubuntu:xenial bash
|
||||
```
|
||||
|
||||
==Lab Book Question: Using Docker, can you access anything outside of the chroot? As a normal user? As root? How much isolation does it provide? How does this compare to a full VM, for example in oVirt?==
|
||||
|
||||
**BEFORE YOU EXIT THE SAFETY OF THE DOCKER CONTAINER**, run:
|
||||
|
||||
```bash
|
||||
rm -rf /
|
||||
```
|
||||
|
||||
> **This deletes everything!**
|
||||
|
||||
What can you see in /, /opt, /proc of the container?
|
||||
|
||||
> Press Ctrl-D to exit the container.
|
||||
|
||||
What can you see in /, /opt, /proc?
|
||||
|
||||
Docker can grant containers to access files or the network.
|
||||
|
||||
Run a container with access to a secret file:
|
||||
|
||||
```bash
|
||||
echo "my secret" > \~/mysecret
|
||||
|
||||
sudo docker run -v \$HOME/mysecret:/srv/mysecret:ro -it ubuntu:xenial sh
|
||||
```
|
||||
|
||||
Access the file within the container:
|
||||
|
||||
```bash
|
||||
cat /srv/mysecret
|
||||
```
|
||||
|
||||
Attempt to write to the file within the container.
|
||||
|
||||
> Press Ctrl-D to exit the container.
|
||||
|
||||
==Lab Book Question: How does Docker's file sharing feature work?==
|
||||
|
||||
Note that our various containers are still running:
|
||||
|
||||
```bash
|
||||
sudo docker ps -a
|
||||
```
|
||||
|
||||
Containers can be stopped, run:
|
||||
|
||||
```bash
|
||||
sudo docker stop CONTAINER_ID
|
||||
```
|
||||
|
||||
> Where container\_id is one of the containers on your system.
|
||||
|
||||
Or to stop them all:
|
||||
|
||||
```bash
|
||||
sudo docker stop $(docker ps -a -q)
|
||||
```
|
||||
And containers can be deleted:
|
||||
|
||||
```bash
|
||||
sudo docker rm CONTAINER_ID
|
||||
```
|
||||
|
||||
And to delete all the containers that are stopped:
|
||||
|
||||
```bash
|
||||
sudo docker container prune
|
||||
```
|
||||
@@ -0,0 +1,32 @@
|
||||
# Containers: Chroot and Docker
|
||||
|
||||
## Getting started
|
||||
### VMs in this lab
|
||||
|
||||
==Start these VMs== (if you haven't already):
|
||||
- hackerbot_server (leave it running, you don't log into this)
|
||||
- desktop (you can sudo to get superuser access)
|
||||
- server (<%= $server_ip %>, you can ssh to this machine, but you don't have superuser access)
|
||||
|
||||
### Your login details for the "desktop" and "server" VMs
|
||||
User: <%= $main_user %>
|
||||
Password: tiaspbiqe2r (**t**his **i**s **a** **s**ecure **p**assword **b**ut **i**s **q**uite **e**asy **2** **r**emember)
|
||||
|
||||
|
||||
|
||||
You won't login to the hackerbot_server, but the VM needs to be running to complete the lab.
|
||||
|
||||
### For marks in the module
|
||||
1. **You need to submit flags**. Note that the flags and the challenges in your VMs are different to other's in the class. Flags will be revealed to you as you complete challenges throughout the module. Flags look like this: ==flag{*somethingrandom*}==. Follow the link on the module page to submit your flags.
|
||||
2. **You need to document the work and your solutions in a Log Book**. This needs to include screenshots (including the flags) of how you solved each Hackerbot challenge and a writeup describing your solution to each challenge, and answering any "Log Book Questions". The Log Book will be submitted later in the semester.
|
||||
|
||||
## Meet Hackerbot!
|
||||

|
||||
|
||||
This exercise involves interacting with Hackerbot, a chatbot who will attack your system. If you satisfy Hackerbot by completing the challenges she will reveal flags to you.
|
||||
|
||||
> If Hackerbot seems to be waiting or halted, simply say 'hi'
|
||||
|
||||
Work through the below exercises, completing the Hackerbot challenges as noted.
|
||||
|
||||
---
|
||||
@@ -0,0 +1,135 @@
|
||||
<%
|
||||
require 'json'
|
||||
require 'securerandom'
|
||||
require 'digest/sha1'
|
||||
require 'fileutils'
|
||||
require 'erb'
|
||||
|
||||
if self.accounts.empty?
|
||||
abort('Sorry, you need to provide an account')
|
||||
end
|
||||
|
||||
$first_account = JSON.parse(self.accounts.first)
|
||||
$main_user = $first_account['username'].to_s
|
||||
$main_user_pass = $first_account['password'].to_s
|
||||
|
||||
# $second_account = JSON.parse(self.accounts[1])
|
||||
# $second_user = $second_account['username'].to_s
|
||||
# $second_password = $second_account['password'].to_s
|
||||
#
|
||||
# $third_account = JSON.parse(self.accounts[2])
|
||||
# $third_user = $third_account['username'].to_s
|
||||
# $third_password = $third_account['password'].to_s
|
||||
|
||||
# $fourth_account = JSON.parse(self.accounts[3])
|
||||
# $fourth_user = $third_account['username'].to_s
|
||||
# $fourth_password = $third_account['password'].to_s
|
||||
|
||||
$server_ip = self.server_ip.first
|
||||
$root_password = self.root_password
|
||||
$flags = self.flags
|
||||
|
||||
REQUIRED_FLAGS = 0
|
||||
while $flags.length < REQUIRED_FLAGS
|
||||
$flags << "flag{#{SecureRandom.hex}}"
|
||||
Print.err "Warning: Not enough flags provided to hackerbot_config generator, some flags won't be tracked/marked!"
|
||||
end
|
||||
|
||||
def get_binding
|
||||
binding
|
||||
end
|
||||
-%>
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<hackerbot
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.github/cliffe/SecGen/hackerbot">
|
||||
<!--<hackerbot xmlns="http://www.github/cliffe/SecGen/hackerbotz"-->
|
||||
|
||||
<name>Hackerbot</name>
|
||||
|
||||
<AIML_chatbot_rules>config/AIML</AIML_chatbot_rules>
|
||||
|
||||
<!--Method for gaining shell access, can be overwritten per-attack-->
|
||||
<get_shell>sshpass -p <%= $root_password %> ssh -oStrictHostKeyChecking=no root@{{chat_ip_address}} /bin/bash</get_shell>
|
||||
|
||||
<messages>
|
||||
<show_attack_numbers />
|
||||
|
||||
<greeting>Hi there. Solve some challenges and I'll give you some flags.</greeting>
|
||||
|
||||
<!--Must provide alternatives for each message-->
|
||||
<say_ready>When you are ready, simply say 'ready'.</say_ready>
|
||||
<say_ready>'Ready'?</say_ready>
|
||||
<next>Ok, I'll do what I can to move things along...</next>
|
||||
<next>Moving things along to the next one...</next>
|
||||
<previous>Ok, I'll do what I can to back things up...</previous>
|
||||
<previous>Ok, backing up.</previous>
|
||||
<goto>Ok, skipping it along.</goto>
|
||||
<goto>Let me see what I can do to goto that attack.</goto>
|
||||
<last_attack>That was the last one for now. You can rest easy, until next time... (End.)</last_attack>
|
||||
<last_attack>That was the last one. Game over?</last_attack>
|
||||
<first_attack>You are back to the beginning!</first_attack>
|
||||
<first_attack>This is where it all began.</first_attack>
|
||||
<getting_shell>Doing my thing...</getting_shell>
|
||||
<getting_shell>Here we go...</getting_shell>
|
||||
<got_shell>...</got_shell>
|
||||
<got_shell>....</got_shell>
|
||||
<repeat>Let me know when you are 'ready', if you want to move on say 'next', or 'previous' and I'll move things along.</repeat>
|
||||
<repeat>Say 'ready', 'next', or 'previous'.</repeat>
|
||||
|
||||
<!--Single responses:-->
|
||||
<help>I am waiting for you to say 'ready', 'next', 'previous', 'list', 'goto *X*', or 'answer *X*'</help>
|
||||
<say_answer>Say "The answer is *X*".</say_answer>
|
||||
<no_quiz>There is no question to answer</no_quiz>
|
||||
<correct_answer>Correct</correct_answer>
|
||||
<incorrect_answer>Incorrect</incorrect_answer>
|
||||
<invalid>That's not possible.</invalid>
|
||||
<non_answer>Wouldn't you like to know.</non_answer>
|
||||
|
||||
<!--can be overwritten per-attack-->
|
||||
<shell_fail_message>Oh no. Failed to get shell... You need to let us in.</shell_fail_message>
|
||||
</messages>
|
||||
|
||||
<tutorial_info>
|
||||
<title>Access Controls: ACLs</title>
|
||||
<tutorial><%= ERB.new(File.read self.templates_path + 'intro.md.erb').result(self.get_binding) %></tutorial>
|
||||
<footer>
|
||||
<%= File.read self.templates_path + 'resources.md.erb' %>
|
||||
|
||||
<%= File.read self.templates_path + 'license.md.erb' %>
|
||||
|
||||
Randomised instance generated by [SecGen](http://github.com/cliffe/SecGen) (<%= Time.new.to_s %>)
|
||||
</footer>
|
||||
|
||||
<provide_tutorial>true</provide_tutorial>
|
||||
|
||||
</tutorial_info>
|
||||
|
||||
<attack>
|
||||
<prompt>Nothing else to do this time.</prompt>
|
||||
|
||||
<condition>
|
||||
<output_matches>.*</output_matches>
|
||||
<message>:)</message>
|
||||
<trigger_next_attack />
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>.*</output_matches>
|
||||
<message>:)</message>
|
||||
<trigger_next_attack />
|
||||
</condition>
|
||||
<else_condition>
|
||||
<message>:)</message>
|
||||
</else_condition>
|
||||
|
||||
<tutorial>
|
||||
<%= ERB.new(File.read self.templates_path + 'containers.md.erb').result(self.get_binding) %>
|
||||
</tutorial>
|
||||
|
||||
</attack>
|
||||
|
||||
|
||||
<!-- TODO: add another attack where HB uses a hardlink attack against the SUID program - they have to fix the problem -->
|
||||
|
||||
</hackerbot>
|
||||
@@ -0,0 +1,114 @@
|
||||
<html>
|
||||
<head>
|
||||
<title><%= self.title %></title>
|
||||
</head>
|
||||
<body>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="css/github-markdown.css">
|
||||
<style>
|
||||
.markdown-body {
|
||||
box-sizing: border-box;
|
||||
min-width: 200px;
|
||||
max-width: 980px;
|
||||
margin: 0 auto;
|
||||
padding: 45px;
|
||||
}
|
||||
.markdown-body h4[id^='hackerbot']:after {
|
||||
display: inline-block;
|
||||
float: right;
|
||||
content: url("images/skullandusb.svg");
|
||||
width: 30px;
|
||||
}
|
||||
article {
|
||||
float: right;
|
||||
width: calc(100% - 300px);
|
||||
}
|
||||
.toc {
|
||||
float: left;
|
||||
font-size: smaller;
|
||||
color: #1a1d22;
|
||||
width: 300px;
|
||||
position: fixed;
|
||||
height: calc(100% - 56px);
|
||||
overflow-y: scroll;
|
||||
font-family: sans-serif;
|
||||
margin-top: 50px;
|
||||
}
|
||||
.toc ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin-left: 1em;
|
||||
}
|
||||
.toc li { /* Space between menu items*/
|
||||
margin: 1em 0;
|
||||
}
|
||||
.toc a {
|
||||
color: #1a1d22;
|
||||
text-decoration: none;
|
||||
}
|
||||
.toc a:hover {
|
||||
color: #6c036d;
|
||||
text-decoration: none;
|
||||
}
|
||||
.toc a:visited {
|
||||
color: #1a1d22;
|
||||
text-decoration: none;
|
||||
}
|
||||
.markdown-body pre, .markdown-body code {
|
||||
background-color: #570138;
|
||||
color: whitesmoke;
|
||||
}
|
||||
.markdown-body img[alt="small-left"] {
|
||||
max-width: 100px;
|
||||
float: left;
|
||||
}
|
||||
.markdown-body img[alt="small-right"] {
|
||||
max-width: 100px;
|
||||
float: right;
|
||||
}
|
||||
.markdown-body img[alt="tiny-right"] {
|
||||
max-width: 30px;
|
||||
float: right;
|
||||
}
|
||||
.markdown-body img[alt="small"] {
|
||||
max-width: 100px;
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding: 15px;
|
||||
}
|
||||
mark {
|
||||
background-color: white;
|
||||
color: #5b29bd;
|
||||
font-weight: bolder;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.markdown-body {
|
||||
padding: 15px;
|
||||
min-width: 200px;
|
||||
max-width: 980px;
|
||||
}
|
||||
.toc {
|
||||
float: none;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
height: auto;
|
||||
}
|
||||
article {
|
||||
float: none;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
<div class="toc">
|
||||
<%= self.html_TOC_rendered %>
|
||||
</div>
|
||||
|
||||
<article class="markdown-body">
|
||||
<%= self.html_rendered %>
|
||||
</article>
|
||||
<script src="js/code-prettify/loader/run_prettify.js?autoload=true&skin=sunburst&lang=css"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,6 @@
|
||||
## License
|
||||
This lab by [*Z. Cliffe Schreuders*](http://z.cliffe.schreuders.org) at Leeds Beckett University is licensed under a [*Creative Commons Attribution-ShareAlike 3.0 Unported License*](http://creativecommons.org/licenses/by-sa/3.0/deed.en_GB).
|
||||
|
||||
Included software source code is also licensed under the GNU General Public License, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||

|
||||
@@ -0,0 +1,2 @@
|
||||
# Reading
|
||||
[Z. C. Schreuders, T. McGill, and C. Payne, "The State of the Art of Application Restrictions and Sandboxes: A Survey of Application-oriented Access Controls and their Shortfalls," Computers and Security, Volume 32, Elsevier B.V., 2013. DOI: 10.1016/j.cose.2012.09.007](http://z.cliffe.schreuders.org/publications/Computers&Security%20-%20The%20State%20of%20the%20Art%20of%20Application%20Restrictions%20and%20Sandboxes%20-%20Author%20Version.pdf)
|
||||
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/ruby
|
||||
require_relative '../../../../../../lib/objects/local_hackerbot_config_generator.rb'
|
||||
|
||||
class HB < HackerbotConfigGenerator
|
||||
|
||||
attr_accessor :server_ip
|
||||
|
||||
def initialize
|
||||
super
|
||||
self.module_name = 'Hackerbot Config Generator'
|
||||
self.title = 'FACLs'
|
||||
|
||||
self.local_dir = File.expand_path('../../',__FILE__)
|
||||
self.templates_path = "#{self.local_dir}/templates/"
|
||||
self.config_template_path = "#{self.local_dir}/templates/lab.xml.erb"
|
||||
self.html_template_path = "#{self.local_dir}/templates/labsheet.html.erb"
|
||||
|
||||
self.server_ip = []
|
||||
end
|
||||
|
||||
def get_options_array
|
||||
super + [['--server_ip', GetoptLong::REQUIRED_ARGUMENT]]
|
||||
end
|
||||
|
||||
def process_options(opt, arg)
|
||||
super
|
||||
case opt
|
||||
when '--server_ip'
|
||||
self.server_ip << arg;
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
HB.new.run
|
||||
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<generator xmlns="http://www.github/cliffe/SecGen/generator"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.github/cliffe/SecGen/generator">
|
||||
<name>Hackerbot config for an access control lab</name>
|
||||
<author>Z. Cliffe Schreuders</author>
|
||||
<module_license>GPLv3</module_license>
|
||||
<description>Generates a config file for a hackerbot for an integrity lab.
|
||||
Topics covered: .</description>
|
||||
|
||||
<type>hackerbot_config</type>
|
||||
<platform>linux</platform>
|
||||
|
||||
<read_fact>accounts</read_fact>
|
||||
<read_fact>flags</read_fact>
|
||||
<read_fact>root_password</read_fact>
|
||||
|
||||
<!--TODO: require input, such as accounts, or fail?-->
|
||||
|
||||
<default_input into="accounts">
|
||||
<generator type="account">
|
||||
<input into="username">
|
||||
<value>vagrant</value>
|
||||
</input>
|
||||
</generator>
|
||||
</default_input>
|
||||
|
||||
<default_input into="flags">
|
||||
<generator type="flag_generator"/>
|
||||
<generator type="flag_generator"/>
|
||||
</default_input>
|
||||
|
||||
<default_input into="root_password">
|
||||
<value>puppet</value>
|
||||
</default_input>
|
||||
|
||||
<output_type>hackerbot</output_type>
|
||||
|
||||
</generator>
|
||||
@@ -0,0 +1,29 @@
|
||||
<html>
|
||||
<head>
|
||||
<title><%= self.title %></title>
|
||||
</head>
|
||||
<body>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="css/github-markdown.css">
|
||||
<style>
|
||||
.markdown-body {
|
||||
box-sizing: border-box;
|
||||
min-width: 200px;
|
||||
max-width: 980px;
|
||||
margin: 0 auto;
|
||||
padding: 45px;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.markdown-body {
|
||||
padding: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<article class="markdown-body">
|
||||
|
||||
<%= self.html_rendered %>
|
||||
|
||||
</article>
|
||||
<script src="js/code-prettify/loader/run_prettify.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,4 @@
|
||||
## License
|
||||
This lab by [*Z. Cliffe Schreuders*](http://z.cliffe.schreuders.org) at Leeds Beckett University is licensed under a [*Creative Commons Attribution-ShareAlike 3.0 Unported License*](http://creativecommons.org/licenses/by-sa/3.0/deed.en_GB).
|
||||
|
||||
Included software source code is also licensed under the GNU General Public License, either version 3 of the License, or (at your option) any later version.
|
||||
@@ -0,0 +1,186 @@
|
||||
## Introducing Full Access Control List (ACL) File Permissions
|
||||
|
||||
An *access control list (ACL)* is attached to an object (resource) and lists all the subjects (users / active entities) that are allowed access, along with the kind of access that is authorised.
|
||||
|
||||
We have explored standard Unix file permissions, which is an abbreviated (simplified) form of ACL. With standard Unix file permissions all authorisation is defined in terms of the owning user (u), groups (g), and others (o), and the type of access that can be granted are read (r), write (r), and execute (x) -- along with some special permission flags, SUID, SGID, and stickybit, which change the meaning of these.
|
||||
|
||||
The Unix file permissions (0664) `-rw-rw-r-- 1 user1 group1 5 Feb 5 test` can be thought of as a simplified ACL with:
|
||||
|
||||
Subject | Permission
|
||||
--- | ---
|
||||
user1 | read, write
|
||||
members of group1 | read, write
|
||||
everyone else | read
|
||||
|
||||
While this is an effective way of representing permissions, and is often adequate, using these traditional Unix file permissions there is no way of representing more complicated rules, such as also granting specific users access to write the file without making them members of group1.
|
||||
|
||||
Modern systems (Windows, Linux, and some other Unix-based systems) now have more complete (and complicated) ACL support, enabling more fine-grained control over authorisation.
|
||||
|
||||
A more expressive ACL for a file can represent a state such as:
|
||||
|
||||
Subject | Permission
|
||||
--- | ---
|
||||
user1 | read, write
|
||||
user2 | read, write
|
||||
members of group1 | read, write
|
||||
members of group2 | read
|
||||
everyone else | nothing
|
||||
|
||||
## Linux Extended ACLs
|
||||
|
||||
Linux now has support for full ACLs (known as Linux ACLs or POSIX ACLs). Linux ACLs can include entries for named users and named groups.
|
||||
|
||||
ACLs require compatible filesystems so that they can be stored. Linux ACLs are saved as extended attributes (EA), which are used to associate metadata with files.
|
||||
|
||||
Linux ACLs that are equivalent with Unix file permissions are known as **minimal ACLs**. Linux ACLs with more than these three entries (owner user, owner group, and others) are known as **extended ACLs**. Below is a table showing the types of subjects present in Linux ACLs.
|
||||
|
||||
Subject type | Text representation
|
||||
--- | ---
|
||||
Owner | user::rwx
|
||||
Named user | user:name:rwx
|
||||
Owning group | group::rwx
|
||||
Named group | group:name:rwx
|
||||
Mask | mask::rwx
|
||||
Other | other::rwx
|
||||
|
||||
The Owner (user::xxx) and Other (other:xxx) permissions are automatically synced to the matching Unix file permission bits.
|
||||
|
||||
==Set a file ACL on your mysecret file==, using the setfacl command:
|
||||
|
||||
```bash
|
||||
setfacl -m u:user2:r ~/mysecret
|
||||
```
|
||||
|
||||
> The `-m` flag specifies that the ACL is to be modified
|
||||
> `u:` or `user:` specifies a rule for a named user
|
||||
> `g:` or `group:` could be used for a named group
|
||||
> This is followed by the name of the user or group
|
||||
> Finally read (r), write (w), and/or execute (x) can be specified using letters (rwx) or a number (7, which is the octet representing wrx)
|
||||
|
||||
This grants user2 read access to the file (without requiring access granted to any other groups or users).
|
||||
|
||||
==Confirm you can access the file from user2:==
|
||||
|
||||
```bash
|
||||
su - user2
|
||||
cat /home/user1/mysecret
|
||||
exit
|
||||
```
|
||||
|
||||
Note that the stat program is not usually ACL aware, so won't report anything out of the usual. ==Run:==
|
||||
|
||||
```bash
|
||||
stat ~/mysecret
|
||||
```
|
||||
|
||||
The ls program can be used to detect File ACLs. ==Run:==
|
||||
|
||||
```bash
|
||||
ls -la ~/mysecret
|
||||
```
|
||||
|
||||
`-rw-r-----+ 1 user1 user1 22 Feb 28 11:47 mysecret`
|
||||
|
||||
Note that the output includes a `+`. This indicates an ACL is in place.
|
||||
|
||||
==Use getfacl to display the permissions:==
|
||||
|
||||
```bash
|
||||
getfacl ~/mysecret
|
||||
```
|
||||
|
||||
## Mask
|
||||
|
||||
Extended ACLs contain a mask entry that defines the upper bound (maximum permissions) that can be assigned by the ACL rules that apply to any named users or groups. This mask (mask::xxx) is typically automatically updated to the union (maximum) of all permissions granted, and automatically synced with the value of the group Unix file permission bits.
|
||||
|
||||
==Grant full rwx permission to user2:==
|
||||
|
||||
```bash
|
||||
setfacl -m u:user2:rwx ~/mysecret
|
||||
```
|
||||
|
||||
==View the updated permissions visible via `ls`:==
|
||||
|
||||
```bash
|
||||
ls -la ~/mysecret
|
||||
```
|
||||
|
||||
Note that the group file permission has changed (in addition to the `+`, this helps to show the level of permission that can result from the new ACL rule.
|
||||
|
||||
Again ==use getfacl to display the ACL rules:==
|
||||
|
||||
```bash
|
||||
getfacl ~/mysecret
|
||||
```
|
||||
|
||||
Note that the mask has changed.
|
||||
|
||||
==Change the mask value to "r"==
|
||||
> Hint: see the table above that describes the text representation.
|
||||
|
||||
==Confirm user2 can no longer access the file due to the mask, even though they have rwx permission.==
|
||||
|
||||
## Understanding the access check behaviour
|
||||
|
||||
The decision making logic has been described as follows:
|
||||
|
||||
>If
|
||||
>>the user ID of the process is the owner, the owner entry determines access
|
||||
|
||||
>else if
|
||||
>>the user ID of the process matches the qualifier in one of the named user entries, this entry determines access
|
||||
|
||||
>else if
|
||||
>>one of the group IDs of the process matches the owning group and the owning group entry contains the requested permissions, this entry determines access
|
||||
|
||||
>else if
|
||||
>>one of the group IDs of the process matches the qualifier of one of the named group entries and this entry contains the requested permissions, this entry determines access
|
||||
|
||||
>else if
|
||||
>>one of the group IDs of the process matches the owning group or any of the named group entries, but neither the owning group entry nor any of the matching named group entries contains the requested permissions, this determines that access is denied
|
||||
|
||||
>else
|
||||
>>the other entry determines access.
|
||||
|
||||
>If
|
||||
>>the matching entry resulting from this selection is the owner or other entry and it contains the requested permissions, access is granted
|
||||
|
||||
>else if
|
||||
>>the matching entry is a named user, owning group, or named group entry and this entry contains the requested permissions and the mask entry also contains the requested permissions (or there is no mask entry), access is granted
|
||||
|
||||
>else
|
||||
>>access is denied.
|
||||
|
||||
Quoted from (Grünbacher, 2003) [^1]
|
||||
|
||||
## Default ACLs
|
||||
|
||||
Directories can have two kinds of ACLs: **access ACLs** (which define the actual rules applied -- this is what we have been using so far), and **default ACLs**.
|
||||
|
||||
Default ACLs set the ACL rules that are applied to any new files created in the directory. Directories created inherit the default ACL, as the new access ACL and default ACL.
|
||||
|
||||
When a default ACL is specified on the parent directory, `umask` has no effect on the permissions of new files.
|
||||
|
||||
==Create a directory to share with user2:==
|
||||
|
||||
```bash
|
||||
mkdir shared
|
||||
setfacl -m u:user2:rw -d -m u:user2:rw shared
|
||||
```
|
||||
|
||||
==Create a new file in the shared directory.==
|
||||
|
||||
==View the ACL created on the new file.==
|
||||
|
||||
|
||||
## Comparison with Windows ACLs
|
||||
Windows file permissions are similar to Linux ACLs, although they are slightly more complicated.
|
||||
|
||||
On Windows permissions are dynamically inherited and checked at access time. Changing permissions on a directory can change the permissions applied to the files within (or even changing the permissions of a directory's parent directory!). Linux ACLs only inherit permissions from default ACLs when they are created, and there is no complicated checking of all the parent directories to calculate access permissions.
|
||||
|
||||
Windows has lots more kinds of access that can be assigned (including append and delete permissions, and ACLs can contain rules about inheritance logic, and deny permissions), compared to Linux ACLs that define rules in terms of read, write, and execute (rwx).
|
||||
|
||||
Linux ACLs use local UIDs and GIDs to assign identity to all subjects (even when authenticating against remote servers, local UIDs are generated). Windows uses global security identifers (SIDs) that can be local or for domain users (authenticated against a domain controller, the global SID is used on ACLs).
|
||||
|
||||
==Log Book Question: Describe an example of how the results would differ between how Linux ACLs and Windows ACLs grant permissions.==
|
||||
> Consider how permissions work for files inside nested directories that have inherited ACLs, and whether Linux ACLs include deny rules.==
|
||||
@@ -0,0 +1,34 @@
|
||||
# Access Controls: Access Control Lists
|
||||
|
||||
## Getting started
|
||||
### VMs in this lab
|
||||
|
||||
==Start these VMs== (if you haven't already):
|
||||
- hackerbot_server (leave it running, you don't log into this)
|
||||
- desktop (you can sudo to get superuser access)
|
||||
- server (<%= $server_ip %>, you can ssh to this machine, but you don't have superuser access)
|
||||
|
||||
### Your login details for the "desktop" and "server" VMs
|
||||
User 1: <%= $main_user %>
|
||||
Password: tiaspbiqe2r (**t**his **i**s **a** **s**ecure **p**assword **b**ut **i**s **q**uite **e**asy **2** **r**emember)
|
||||
|
||||
User 2: <%= $second_user %>
|
||||
Password: <%= $second_password %>
|
||||
|
||||
|
||||
You won't login to the hackerbot_server, but the VM needs to be running to complete the lab.
|
||||
|
||||
### For marks in the module
|
||||
1. **You need to submit flags**. Note that the flags and the challenges in your VMs are different to other's in the class. Flags will be revealed to you as you complete challenges throughout the module. Flags look like this: ==flag{*somethingrandom*}==. Follow the link on the module page to submit your flags.
|
||||
2. **You need to document the work and your solutions in a Log Book**. This needs to include screenshots (including the flags) of how you solved each Hackerbot challenge and a writeup describing your solution to each challenge, and answering any "Log Book Questions". The Log Book will be submitted later in the semester.
|
||||
|
||||
## Meet Hackerbot!
|
||||

|
||||
|
||||
This exercise involves interacting with Hackerbot, a chatbot who will attack your system. If you satisfy Hackerbot by completing the challenges she will reveal flags to you.
|
||||
|
||||
> If Hackerbot seems to be waiting or halted, simply say 'hi'
|
||||
|
||||
Work through the below exercises, completing the Hackerbot challenges as noted.
|
||||
|
||||
---
|
||||
@@ -0,0 +1,220 @@
|
||||
<%
|
||||
require 'json'
|
||||
require 'securerandom'
|
||||
require 'digest/sha1'
|
||||
require 'fileutils'
|
||||
require 'erb'
|
||||
|
||||
if self.accounts.empty?
|
||||
abort('Sorry, you need to provide an account')
|
||||
end
|
||||
|
||||
$first_account = JSON.parse(self.accounts.first)
|
||||
$main_user = $first_account['username'].to_s
|
||||
$main_user_pass = $first_account['password'].to_s
|
||||
|
||||
$second_account = JSON.parse(self.accounts[1])
|
||||
$second_user = $second_account['username'].to_s
|
||||
$second_password = $second_account['password'].to_s
|
||||
|
||||
$third_account = JSON.parse(self.accounts[2])
|
||||
$third_user = $third_account['username'].to_s
|
||||
$third_password = $third_account['password'].to_s
|
||||
|
||||
# $fourth_account = JSON.parse(self.accounts[3])
|
||||
# $fourth_user = $third_account['username'].to_s
|
||||
# $fourth_password = $third_account['password'].to_s
|
||||
|
||||
$server_ip = self.server_ip.first
|
||||
$root_password = self.root_password
|
||||
$flags = self.flags
|
||||
|
||||
REQUIRED_FLAGS = 2
|
||||
while $flags.length < REQUIRED_FLAGS
|
||||
$flags << "flag{#{SecureRandom.hex}}"
|
||||
Print.err "Warning: Not enough flags provided to hackerbot_config generator, some flags won't be tracked/marked!"
|
||||
end
|
||||
|
||||
def get_binding
|
||||
binding
|
||||
end
|
||||
-%>
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<hackerbot
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.github/cliffe/SecGen/hackerbot">
|
||||
<!--<hackerbot xmlns="http://www.github/cliffe/SecGen/hackerbotz"-->
|
||||
|
||||
<name>Hackerbot</name>
|
||||
|
||||
<AIML_chatbot_rules>config/AIML</AIML_chatbot_rules>
|
||||
|
||||
<!--Method for gaining shell access, can be overwritten per-attack-->
|
||||
<get_shell>sshpass -p <%= $root_password %> ssh -oStrictHostKeyChecking=no root@{{chat_ip_address}} /bin/bash</get_shell>
|
||||
|
||||
<messages>
|
||||
<show_attack_numbers />
|
||||
|
||||
<greeting>Hi there. Solve some challenges and I'll give you some flags.</greeting>
|
||||
|
||||
<!--Must provide alternatives for each message-->
|
||||
<say_ready>When you are ready, simply say 'ready'.</say_ready>
|
||||
<say_ready>'Ready'?</say_ready>
|
||||
<next>Ok, I'll do what I can to move things along...</next>
|
||||
<next>Moving things along to the next one...</next>
|
||||
<previous>Ok, I'll do what I can to back things up...</previous>
|
||||
<previous>Ok, backing up.</previous>
|
||||
<goto>Ok, skipping it along.</goto>
|
||||
<goto>Let me see what I can do to goto that attack.</goto>
|
||||
<last_attack>That was the last one for now. You can rest easy, until next time... (End.)</last_attack>
|
||||
<last_attack>That was the last one. Game over?</last_attack>
|
||||
<first_attack>You are back to the beginning!</first_attack>
|
||||
<first_attack>This is where it all began.</first_attack>
|
||||
<getting_shell>Doing my thing...</getting_shell>
|
||||
<getting_shell>Here we go...</getting_shell>
|
||||
<got_shell>...</got_shell>
|
||||
<got_shell>....</got_shell>
|
||||
<repeat>Let me know when you are 'ready', if you want to move on say 'next', or 'previous' and I'll move things along.</repeat>
|
||||
<repeat>Say 'ready', 'next', or 'previous'.</repeat>
|
||||
|
||||
<!--Single responses:-->
|
||||
<help>I am waiting for you to say 'ready', 'next', 'previous', 'list', 'goto *X*', or 'answer *X*'</help>
|
||||
<say_answer>Say "The answer is *X*".</say_answer>
|
||||
<no_quiz>There is no question to answer</no_quiz>
|
||||
<correct_answer>Correct</correct_answer>
|
||||
<incorrect_answer>Incorrect</incorrect_answer>
|
||||
<invalid>That's not possible.</invalid>
|
||||
<non_answer>Wouldn't you like to know.</non_answer>
|
||||
|
||||
<!--can be overwritten per-attack-->
|
||||
<shell_fail_message>Oh no. Failed to get shell... You need to let us in.</shell_fail_message>
|
||||
</messages>
|
||||
|
||||
<tutorial_info>
|
||||
<title>Access Controls: ACLs</title>
|
||||
<tutorial><%= ERB.new(File.read self.templates_path + 'intro.md.erb').result(self.get_binding) %></tutorial>
|
||||
<footer>
|
||||
<%= File.read self.templates_path + 'resources.md.erb' %>
|
||||
|
||||
<%= File.read self.templates_path + 'license.md.erb' %>
|
||||
|
||||
Randomised instance generated by [SecGen](http://github.com/cliffe/SecGen) (<%= Time.new.to_s %>)
|
||||
</footer>
|
||||
|
||||
<provide_tutorial>true</provide_tutorial>
|
||||
|
||||
</tutorial_info>
|
||||
|
||||
<attack>
|
||||
<% $rand_secret4 = "secret#{SecureRandom.hex(3)}" %>
|
||||
<% $rand_secret_file4 = "/home/#{$main_user}/secret#{SecureRandom.hex(3)}" %>
|
||||
<prompt>On your desktop system, create a file, <%= $rand_secret_file4 %>, containing the string <%= $rand_secret4 %>. Make sure the file is owned by <%= $main_user %>. Use Linux ACLs (without using groups) to enable <%= $second_user %> to also read the file, but not write to it. Make sure <%= $third_user %> can't access the file.</prompt>
|
||||
|
||||
<!-- <get_shell>sshpass -p <%= $root_password %> ssh -oStrictHostKeyChecking=no root@<%= $server_ip %> /bin/bash</get_shell> -->
|
||||
|
||||
<post_command>sudo -u <%= $main_user %> grep <%= $rand_secret4 %> <%= $rand_secret_file4 %> >/dev/null; echo m-$?-; sudo -u <%= $second_user %> grep <%= $rand_secret4 %> <%= $rand_secret_file4 %> >/dev/null; echo s-$?-; sudo -u <%= $third_user %> grep <%= $rand_secret4 %> <%= $rand_secret_file4 %> >/dev/null; echo t-$?-; sudo -u <%= $third_user %> bash -c 'echo "hackerbot/<%= $third_user %> was here!" > <%= $rand_secret_file4 %>' >/dev/null; echo tw-$?-; ls -l <%= $rand_secret_file4 %> | grep +; echo f-$?- ; getfacl <%= $rand_secret_file4 %> | grep '^group:[^:]'; echo g-$?- </post_command>
|
||||
|
||||
<condition>
|
||||
<output_matches>No such file or directory</output_matches>
|
||||
<message>:( It looks like the file might not exist.</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>m-0-.*s-0-.*t-2-.*f-0-.*g-1-</output_matches>
|
||||
<message>:) Well done! <%= $flags.pop %></message>
|
||||
<trigger_next_attack />
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>m-0-.*s-0-.*t-2-.*f-1-</output_matches>
|
||||
<message>:P Looks like you got all the file access working, but you are supposed to use facls without groups for this task!</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>tw-0-</output_matches>
|
||||
<message>:( Your file wasn't protected from <%= $third_user %>!</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>t-0-</output_matches>
|
||||
<message>:( Looks like <%= $third_user %> can read the file... Use groups and set permissions to make sure they can't do so...</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>m-0-.*s-0-</output_matches>
|
||||
<message>:( Looks like <%= $main_user %> and <%= $second_user %> can access the file... Almost there. Make sure <%= $third_user %> doesn't have permission to access it.</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>s-0-</output_matches>
|
||||
<message>:( Looks like <%= $second_user %> can access the file... But not <%= $main_user %>. Almost there...</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>s-2-</output_matches>
|
||||
<message>:( Looks like <%= $second_user %> can't access the file... Use ACLs to make sure they can... (Hint: Consider the directory and file permissions)</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>m-0-</output_matches>
|
||||
<message>:( Looks like <%= $main_user %> can access the file... Almost there...</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>m-1-|s-1-</output_matches>
|
||||
<message>:( Looks like the file has the wrong contents...</message>
|
||||
</condition>
|
||||
<else_condition>
|
||||
<message>:( Something was not right</message>
|
||||
</else_condition>
|
||||
|
||||
<tutorial><%= ERB.new(File.read self.templates_path + 'facls.md.erb').result(self.get_binding) %></tutorial>
|
||||
|
||||
</attack>
|
||||
|
||||
|
||||
<attack>
|
||||
<% $rand_shared_dir = "/home/#{$main_user}/shared#{SecureRandom.hex(3)}/" %>
|
||||
<prompt>On your desktop system, create a directory, <%= $rand_shared_dir %>. Make sure the directory is owned by <%= $main_user %>. Use Linux ACLs (but not groups) to enable <%= $second_user %> and <%= $third_user %> to also create shared files in the directory (read and write for all three users), but not available to other users.</prompt>
|
||||
|
||||
<post_command>sudo -u <%= $main_user %> bash -c 'echo "<%= $main_user %> was here!" > <%= $rand_shared_dir %>shared_file' >/dev/null; echo m-$?-; sudo -u <%= $second_user %> bash -c 'echo "<%= $second_user %> was here!" >> <%= $rand_shared_dir %>shared_file' >/dev/null; echo s-$?-; sudo -u <%= $third_user %> bash -c 'echo "<%= $third_user %> was here!" >> <%= $rand_shared_dir %>shared_file' >/dev/null; echo t-$?-; ls -l <%= $rand_shared_dir %>shared_file | grep +; echo f-$?- ; getfacl <%= $rand_shared_dir %>shared_file | grep '^group:[^:]'; echo g-$?-; getfacl <%= $rand_shared_dir %>shared_file | grep '^other::---'; echo o-$?-; rm <%= $rand_shared_dir %>shared_file </post_command>
|
||||
|
||||
<condition>
|
||||
<output_matches>No such file or directory</output_matches>
|
||||
<message>:( It looks like the directory might not exist (or perhaps a permissions issue).</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>m-0-.*s-0-.*t-0-.*f-0-.*g-1-.*o-0-</output_matches>
|
||||
<message>:) Well done! <%= $flags.pop %></message>
|
||||
<trigger_next_attack />
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>m-0-.*s-0-.*t-0-.*f-1-</output_matches>
|
||||
<message>:P Looks like you got all the file access working, but you are supposed to use facls for this task! Hint: Make sure you have set a default ACL.</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>o-[1-9]+-</output_matches>
|
||||
<message>:( Other users can access files in your shared directory. Hint: consider using default ACLs.</message>
|
||||
</condition>
|
||||
<else_condition>
|
||||
<message>:( Something was not right. Make sure all three users can access the directory to create and share files. </message>
|
||||
</else_condition>
|
||||
|
||||
</attack>
|
||||
|
||||
|
||||
|
||||
<attack>
|
||||
|
||||
<prompt>There is a file permissions problem on the server, which could enable normal users to read any files. There is a flag to be found in a home directory. This is the end.</prompt>
|
||||
|
||||
<condition>
|
||||
<output_matches>.*</output_matches>
|
||||
<message>8-)</message>
|
||||
<trigger_next_attack />
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>.*</output_matches>
|
||||
<message>:)</message>
|
||||
<trigger_next_attack />
|
||||
</condition>
|
||||
<else_condition>
|
||||
<message>:)</message>
|
||||
</else_condition>
|
||||
|
||||
</attack>
|
||||
|
||||
|
||||
</hackerbot>
|
||||
@@ -0,0 +1,114 @@
|
||||
<html>
|
||||
<head>
|
||||
<title><%= self.title %></title>
|
||||
</head>
|
||||
<body>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="css/github-markdown.css">
|
||||
<style>
|
||||
.markdown-body {
|
||||
box-sizing: border-box;
|
||||
min-width: 200px;
|
||||
max-width: 980px;
|
||||
margin: 0 auto;
|
||||
padding: 45px;
|
||||
}
|
||||
.markdown-body h4[id^='hackerbot']:after {
|
||||
display: inline-block;
|
||||
float: right;
|
||||
content: url("images/skullandusb.svg");
|
||||
width: 30px;
|
||||
}
|
||||
article {
|
||||
float: right;
|
||||
width: calc(100% - 300px);
|
||||
}
|
||||
.toc {
|
||||
float: left;
|
||||
font-size: smaller;
|
||||
color: #1a1d22;
|
||||
width: 300px;
|
||||
position: fixed;
|
||||
height: calc(100% - 56px);
|
||||
overflow-y: scroll;
|
||||
font-family: sans-serif;
|
||||
margin-top: 50px;
|
||||
}
|
||||
.toc ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin-left: 1em;
|
||||
}
|
||||
.toc li { /* Space between menu items*/
|
||||
margin: 1em 0;
|
||||
}
|
||||
.toc a {
|
||||
color: #1a1d22;
|
||||
text-decoration: none;
|
||||
}
|
||||
.toc a:hover {
|
||||
color: #6c036d;
|
||||
text-decoration: none;
|
||||
}
|
||||
.toc a:visited {
|
||||
color: #1a1d22;
|
||||
text-decoration: none;
|
||||
}
|
||||
.markdown-body pre, .markdown-body code {
|
||||
background-color: #570138;
|
||||
color: whitesmoke;
|
||||
}
|
||||
.markdown-body img[alt="small-left"] {
|
||||
max-width: 100px;
|
||||
float: left;
|
||||
}
|
||||
.markdown-body img[alt="small-right"] {
|
||||
max-width: 100px;
|
||||
float: right;
|
||||
}
|
||||
.markdown-body img[alt="tiny-right"] {
|
||||
max-width: 30px;
|
||||
float: right;
|
||||
}
|
||||
.markdown-body img[alt="small"] {
|
||||
max-width: 100px;
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding: 15px;
|
||||
}
|
||||
mark {
|
||||
background-color: white;
|
||||
color: #5b29bd;
|
||||
font-weight: bolder;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.markdown-body {
|
||||
padding: 15px;
|
||||
min-width: 200px;
|
||||
max-width: 980px;
|
||||
}
|
||||
.toc {
|
||||
float: none;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
height: auto;
|
||||
}
|
||||
article {
|
||||
float: none;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
<div class="toc">
|
||||
<%= self.html_TOC_rendered %>
|
||||
</div>
|
||||
|
||||
<article class="markdown-body">
|
||||
<%= self.html_rendered %>
|
||||
</article>
|
||||
<script src="js/code-prettify/loader/run_prettify.js?autoload=true&skin=sunburst&lang=css"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,6 @@
|
||||
## License
|
||||
This lab by [*Z. Cliffe Schreuders*](http://z.cliffe.schreuders.org) at Leeds Beckett University is licensed under a [*Creative Commons Attribution-ShareAlike 3.0 Unported License*](http://creativecommons.org/licenses/by-sa/3.0/deed.en_GB).
|
||||
|
||||
Included software source code is also licensed under the GNU General Public License, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||

|
||||
@@ -0,0 +1,4 @@
|
||||
# Resources
|
||||
This excellent paper describes Linux ACL in detail:
|
||||
|
||||
[Grunbacher, Andreas. "POSIX Access Control Lists on Linux." *USENIX Annual Technical Conference*, FREENIX Track. 2003.](https://www.usenix.org/legacy/events/usenix03/tech/freenix03/full_papers/gruenbacher/gruenbacher.pdf)
|
||||
@@ -0,0 +1,35 @@
|
||||
|
||||
# CONVERT THESE INTO HB CHALLENGES
|
||||
==Create a file "~/myshare", and grant everyone read-write access.==
|
||||
|
||||
> Test whether you have correctly set permissions.
|
||||
|
||||
==Create "mygroupshare", grant only read access to everyone in your group.==
|
||||
|
||||
> Test whether you have correctly set permissions.
|
||||
|
||||
Create a new group called "staff", and create a file that you and the other user can collaborate on (both edit).
|
||||
|
||||
> Hint, you should both be added to the group. You may require root access for this task. Your classmate may want to ssh to your system.
|
||||
>
|
||||
> Test whether you have correctly set permissions. Both users should be able to edit the file, yet other users should not have write access.
|
||||
|
||||
Read and write to the shared files created by others, for example:
|
||||
|
||||
```bash
|
||||
cat /home/*dropbear*/myshare
|
||||
```
|
||||
|
||||
**Challenge**:
|
||||
|
||||
```bash
|
||||
mkdir test
|
||||
```
|
||||
|
||||
```bash
|
||||
touch test/test1 test/test2 test/test3
|
||||
```
|
||||
|
||||
> Use a single chmod command to recursively set the permissions for all files contained in the new "test" directory.
|
||||
>
|
||||
> Hint: `man chmod`
|
||||
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/ruby
|
||||
require_relative '../../../../../../lib/objects/local_hackerbot_config_generator.rb'
|
||||
|
||||
class HB < HackerbotConfigGenerator
|
||||
|
||||
attr_accessor :server_ip
|
||||
|
||||
def initialize
|
||||
super
|
||||
self.module_name = 'Hackerbot Config Generator Authentication'
|
||||
self.title = 'Authentication'
|
||||
|
||||
self.local_dir = File.expand_path('../../',__FILE__)
|
||||
self.templates_path = "#{self.local_dir}/templates/"
|
||||
self.config_template_path = "#{self.local_dir}/templates/lab.xml.erb"
|
||||
self.html_template_path = "#{self.local_dir}/templates/labsheet.html.erb"
|
||||
|
||||
self.server_ip = []
|
||||
end
|
||||
|
||||
def get_options_array
|
||||
super + [['--server_ip', GetoptLong::REQUIRED_ARGUMENT]]
|
||||
end
|
||||
|
||||
def process_options(opt, arg)
|
||||
super
|
||||
case opt
|
||||
when '--server_ip'
|
||||
self.server_ip << arg;
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
HB.new.run
|
||||
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<generator xmlns="http://www.github/cliffe/SecGen/generator"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.github/cliffe/SecGen/generator">
|
||||
<name>Hackerbot config for a containers lab</name>
|
||||
<author>Z. Cliffe Schreuders</author>
|
||||
<module_license>GPLv3</module_license>
|
||||
<description>Generates a config file for a hackerbot for an integrity lab.
|
||||
Topics covered: .</description>
|
||||
|
||||
<type>hackerbot_config</type>
|
||||
<platform>linux</platform>
|
||||
|
||||
<read_fact>accounts</read_fact>
|
||||
<read_fact>flags</read_fact>
|
||||
<read_fact>root_password</read_fact>
|
||||
|
||||
<!--TODO: require input, such as accounts, or fail?-->
|
||||
|
||||
<default_input into="accounts">
|
||||
<generator type="account">
|
||||
<input into="username">
|
||||
<value>vagrant</value>
|
||||
</input>
|
||||
</generator>
|
||||
</default_input>
|
||||
|
||||
<default_input into="flags">
|
||||
<generator type="flag_generator"/>
|
||||
<generator type="flag_generator"/>
|
||||
</default_input>
|
||||
|
||||
<default_input into="root_password">
|
||||
<value>puppet</value>
|
||||
</default_input>
|
||||
|
||||
<output_type>hackerbot</output_type>
|
||||
|
||||
</generator>
|
||||
@@ -0,0 +1,29 @@
|
||||
<html>
|
||||
<head>
|
||||
<title><%= self.title %></title>
|
||||
</head>
|
||||
<body>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="css/github-markdown.css">
|
||||
<style>
|
||||
.markdown-body {
|
||||
box-sizing: border-box;
|
||||
min-width: 200px;
|
||||
max-width: 980px;
|
||||
margin: 0 auto;
|
||||
padding: 45px;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.markdown-body {
|
||||
padding: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<article class="markdown-body">
|
||||
|
||||
<%= self.html_rendered %>
|
||||
|
||||
</article>
|
||||
<script src="js/code-prettify/loader/run_prettify.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,4 @@
|
||||
## License
|
||||
This lab by [*Z. Cliffe Schreuders*](http://z.cliffe.schreuders.org) at Leeds Beckett University is licensed under a [*Creative Commons Attribution-ShareAlike 3.0 Unported License*](http://creativecommons.org/licenses/by-sa/3.0/deed.en_GB).
|
||||
|
||||
Included software source code is also licensed under the GNU General Public License, either version 3 of the License, or (at your option) any later version.
|
||||
@@ -0,0 +1,34 @@
|
||||
# Network-based Identity Management and LDAP
|
||||
|
||||
## Getting started
|
||||
### VMs in this lab
|
||||
|
||||
==Start these VMs== (if you haven't already):
|
||||
- hackerbot_server (leave it running, you don't log into this)
|
||||
- desktop (you can sudo to get superuser access)
|
||||
- server (<%= $server_ip %>, you can ssh to this machine, but you don't have superuser access)
|
||||
|
||||
### Your login details for the "desktop" and "server" VMs
|
||||
User 1: <%= $main_user %>
|
||||
Password: tiaspbiqe2r (**t**his **i**s **a** **s**ecure **p**assword **b**ut **i**s **q**uite **e**asy **2** **r**emember)
|
||||
|
||||
User 2: <%= $second_user %>
|
||||
Password: <%= $second_password %>
|
||||
|
||||
|
||||
You won't login to the hackerbot_server, but the VM needs to be running to complete the lab.
|
||||
|
||||
### For marks in the module
|
||||
1. **You need to submit flags**. Note that the flags and the challenges in your VMs are different to other's in the class. Flags will be revealed to you as you complete challenges throughout the module. Flags look like this: ==flag{*somethingrandom*}==. Follow the link on the module page to submit your flags.
|
||||
2. **You need to document the work and your solutions in a Log Book**. This needs to include screenshots (including the flags) of how you solved each Hackerbot challenge and a writeup describing your solution to each challenge, and answering any "Log Book Questions". The Log Book will be submitted later in the semester.
|
||||
|
||||
## Meet Hackerbot!
|
||||

|
||||
|
||||
This exercise involves interacting with Hackerbot, a chatbot who will attack your system. If you satisfy Hackerbot by completing the challenges she will reveal flags to you.
|
||||
|
||||
> If Hackerbot seems to be waiting or halted, simply say 'hi'
|
||||
|
||||
Work through the below exercises, completing the Hackerbot challenges as noted.
|
||||
|
||||
---
|
||||
@@ -0,0 +1,172 @@
|
||||
<%
|
||||
require 'json'
|
||||
require 'securerandom'
|
||||
require 'digest/sha1'
|
||||
require 'fileutils'
|
||||
require 'erb'
|
||||
|
||||
if self.accounts.empty?
|
||||
abort('Sorry, you need to provide an account')
|
||||
end
|
||||
|
||||
$first_account = JSON.parse(self.accounts.first)
|
||||
$main_user = $first_account['username'].to_s
|
||||
$main_user_pass = $first_account['password'].to_s
|
||||
|
||||
$second_account = JSON.parse(self.accounts[1])
|
||||
$second_user = $second_account['username'].to_s
|
||||
$second_password = $second_account['password'].to_s
|
||||
|
||||
$third_account = JSON.parse(self.accounts[2])
|
||||
$third_user = $third_account['username'].to_s
|
||||
$third_password = $third_account['password'].to_s
|
||||
|
||||
# $fourth_account = JSON.parse(self.accounts[3])
|
||||
# $fourth_user = $third_account['username'].to_s
|
||||
# $fourth_password = $third_account['password'].to_s
|
||||
|
||||
$server_ip = self.server_ip.first
|
||||
$root_password = self.root_password
|
||||
$flags = self.flags
|
||||
|
||||
REQUIRED_FLAGS = 2
|
||||
while $flags.length < REQUIRED_FLAGS
|
||||
$flags << "flag{#{SecureRandom.hex}}"
|
||||
Print.err "Warning: Not enough flags provided to hackerbot_config generator, some flags won't be tracked/marked!"
|
||||
end
|
||||
|
||||
def get_binding
|
||||
binding
|
||||
end
|
||||
-%>
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<hackerbot
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.github/cliffe/SecGen/hackerbot">
|
||||
<!--<hackerbot xmlns="http://www.github/cliffe/SecGen/hackerbotz"-->
|
||||
|
||||
<name>Hackerbot</name>
|
||||
|
||||
<AIML_chatbot_rules>config/AIML</AIML_chatbot_rules>
|
||||
|
||||
<!--Method for gaining shell access, can be overwritten per-attack-->
|
||||
<get_shell>sshpass -p <%= $root_password %> ssh -oStrictHostKeyChecking=no root@{{chat_ip_address}} /bin/bash</get_shell>
|
||||
|
||||
<messages>
|
||||
<show_attack_numbers />
|
||||
|
||||
<greeting>Hi there. Solve some challenges and I'll give you some flags.</greeting>
|
||||
|
||||
<!--Must provide alternatives for each message-->
|
||||
<say_ready>When you are ready, simply say 'ready'.</say_ready>
|
||||
<say_ready>'Ready'?</say_ready>
|
||||
<next>Ok, I'll do what I can to move things along...</next>
|
||||
<next>Moving things along to the next one...</next>
|
||||
<previous>Ok, I'll do what I can to back things up...</previous>
|
||||
<previous>Ok, backing up.</previous>
|
||||
<goto>Ok, skipping it along.</goto>
|
||||
<goto>Let me see what I can do to goto that attack.</goto>
|
||||
<last_attack>That was the last one for now. You can rest easy, until next time... (End.)</last_attack>
|
||||
<last_attack>That was the last one. Game over?</last_attack>
|
||||
<first_attack>You are back to the beginning!</first_attack>
|
||||
<first_attack>This is where it all began.</first_attack>
|
||||
<getting_shell>Doing my thing...</getting_shell>
|
||||
<getting_shell>Here we go...</getting_shell>
|
||||
<got_shell>...</got_shell>
|
||||
<got_shell>....</got_shell>
|
||||
<repeat>Let me know when you are 'ready', if you want to move on say 'next', or 'previous' and I'll move things along.</repeat>
|
||||
<repeat>Say 'ready', 'next', or 'previous'.</repeat>
|
||||
|
||||
<!--Single responses:-->
|
||||
<help>I am waiting for you to say 'ready', 'next', 'previous', 'list', 'goto *X*', or 'answer *X*'</help>
|
||||
<say_answer>Say "The answer is *X*".</say_answer>
|
||||
<no_quiz>There is no question to answer</no_quiz>
|
||||
<correct_answer>Correct</correct_answer>
|
||||
<incorrect_answer>Incorrect</incorrect_answer>
|
||||
<invalid>That's not possible.</invalid>
|
||||
<non_answer>Wouldn't you like to know.</non_answer>
|
||||
|
||||
<!--can be overwritten per-attack-->
|
||||
<shell_fail_message>Oh no. Failed to get shell... You need to let us in.</shell_fail_message>
|
||||
</messages>
|
||||
|
||||
<tutorial_info>
|
||||
<title>Access Controls: ACLs</title>
|
||||
<tutorial><%= ERB.new(File.read self.templates_path + 'intro.md.erb').result(self.get_binding) %></tutorial>
|
||||
<footer>
|
||||
<%= File.read self.templates_path + 'resources.md.erb' %>
|
||||
|
||||
<%= File.read self.templates_path + 'license.md.erb' %>
|
||||
|
||||
Randomised instance generated by [SecGen](http://github.com/cliffe/SecGen) (<%= Time.new.to_s %>)
|
||||
</footer>
|
||||
|
||||
<provide_tutorial>true</provide_tutorial>
|
||||
|
||||
</tutorial_info>
|
||||
|
||||
<attack>
|
||||
<% $rand_secret4 = "secret#{SecureRandom.hex(3)}" %>
|
||||
<% $rand_secret_file4 = "/home/#{$main_user}/secret#{SecureRandom.hex(3)}" %>
|
||||
<prompt>On your desktop system, create a file, <%= $rand_secret_file4 %>, containing the string <%= $rand_secret4 %>. Make sure the file is owned by <%= $main_user %>. Use Linux ACLs (without using groups) to enable <%= $second_user %> to also read the file, but not write to it. Make sure <%= $third_user %> can't access the file.</prompt>
|
||||
|
||||
<!-- <get_shell>sshpass -p <%= $root_password %> ssh -oStrictHostKeyChecking=no root@<%= $server_ip %> /bin/bash</get_shell> -->
|
||||
|
||||
<post_command>sudo -u <%= $main_user %> grep <%= $rand_secret4 %> <%= $rand_secret_file4 %> >/dev/null; echo m-$?-; sudo -u <%= $second_user %> grep <%= $rand_secret4 %> <%= $rand_secret_file4 %> >/dev/null; echo s-$?-; sudo -u <%= $third_user %> grep <%= $rand_secret4 %> <%= $rand_secret_file4 %> >/dev/null; echo t-$?-; sudo -u <%= $third_user %> bash -c 'echo "hackerbot/<%= $third_user %> was here!" > <%= $rand_secret_file4 %>' >/dev/null; echo tw-$?-; ls -l <%= $rand_secret_file4 %> | grep +; echo f-$?- ; getfacl <%= $rand_secret_file4 %> | grep '^group:[^:]'; echo g-$?- </post_command>
|
||||
|
||||
<condition>
|
||||
<output_matches>No such file or directory</output_matches>
|
||||
<message>:( It looks like the file might not exist.</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>m-0-.*s-0-.*t-2-.*f-0-.*g-1-</output_matches>
|
||||
<message>:) Well done! <%= $flags.pop %></message>
|
||||
<trigger_next_attack />
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>m-0-.*s-0-.*t-2-.*f-1-</output_matches>
|
||||
<message>:P Looks like you got all the file access working, but you are supposed to use facls without groups for this task!</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>tw-0-</output_matches>
|
||||
<message>:( Your file wasn't protected from <%= $third_user %>!</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>t-0-</output_matches>
|
||||
<message>:( Looks like <%= $third_user %> can read the file... Use groups and set permissions to make sure they can't do so...</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>m-0-.*s-0-</output_matches>
|
||||
<message>:( Looks like <%= $main_user %> and <%= $second_user %> can access the file... Almost there. Make sure <%= $third_user %> doesn't have permission to access it.</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>s-0-</output_matches>
|
||||
<message>:( Looks like <%= $second_user %> can access the file... Almost there...</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>s-2-</output_matches>
|
||||
<message>:( Looks like <%= $second_user %> can't access the file... Use ACLs to make sure they can...</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>m-0-</output_matches>
|
||||
<message>:( Looks like <%= $main_user %> can access the file... Almost there...</message>
|
||||
</condition>
|
||||
<condition>
|
||||
<output_matches>m-1-|s-1-</output_matches>
|
||||
<message>:( Looks like the file has the wrong contents...</message>
|
||||
</condition>
|
||||
<else_condition>
|
||||
<message>:( Something was not right</message>
|
||||
</else_condition>
|
||||
|
||||
<tutorial>
|
||||
<%= ERB.new(File.read self.templates_path + 'network_auth_ldap.md.erb').result(self.get_binding) %>
|
||||
</tutorial>
|
||||
|
||||
</attack>
|
||||
|
||||
|
||||
<!-- TODO: add another attack where HB uses a hardlink attack against the SUID program - they have to fix the problem -->
|
||||
|
||||
</hackerbot>
|
||||
@@ -0,0 +1,114 @@
|
||||
<html>
|
||||
<head>
|
||||
<title><%= self.title %></title>
|
||||
</head>
|
||||
<body>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="css/github-markdown.css">
|
||||
<style>
|
||||
.markdown-body {
|
||||
box-sizing: border-box;
|
||||
min-width: 200px;
|
||||
max-width: 980px;
|
||||
margin: 0 auto;
|
||||
padding: 45px;
|
||||
}
|
||||
.markdown-body h4[id^='hackerbot']:after {
|
||||
display: inline-block;
|
||||
float: right;
|
||||
content: url("images/skullandusb.svg");
|
||||
width: 30px;
|
||||
}
|
||||
article {
|
||||
float: right;
|
||||
width: calc(100% - 300px);
|
||||
}
|
||||
.toc {
|
||||
float: left;
|
||||
font-size: smaller;
|
||||
color: #1a1d22;
|
||||
width: 300px;
|
||||
position: fixed;
|
||||
height: calc(100% - 56px);
|
||||
overflow-y: scroll;
|
||||
font-family: sans-serif;
|
||||
margin-top: 50px;
|
||||
}
|
||||
.toc ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin-left: 1em;
|
||||
}
|
||||
.toc li { /* Space between menu items*/
|
||||
margin: 1em 0;
|
||||
}
|
||||
.toc a {
|
||||
color: #1a1d22;
|
||||
text-decoration: none;
|
||||
}
|
||||
.toc a:hover {
|
||||
color: #6c036d;
|
||||
text-decoration: none;
|
||||
}
|
||||
.toc a:visited {
|
||||
color: #1a1d22;
|
||||
text-decoration: none;
|
||||
}
|
||||
.markdown-body pre, .markdown-body code {
|
||||
background-color: #570138;
|
||||
color: whitesmoke;
|
||||
}
|
||||
.markdown-body img[alt="small-left"] {
|
||||
max-width: 100px;
|
||||
float: left;
|
||||
}
|
||||
.markdown-body img[alt="small-right"] {
|
||||
max-width: 100px;
|
||||
float: right;
|
||||
}
|
||||
.markdown-body img[alt="tiny-right"] {
|
||||
max-width: 30px;
|
||||
float: right;
|
||||
}
|
||||
.markdown-body img[alt="small"] {
|
||||
max-width: 100px;
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding: 15px;
|
||||
}
|
||||
mark {
|
||||
background-color: white;
|
||||
color: #5b29bd;
|
||||
font-weight: bolder;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.markdown-body {
|
||||
padding: 15px;
|
||||
min-width: 200px;
|
||||
max-width: 980px;
|
||||
}
|
||||
.toc {
|
||||
float: none;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
height: auto;
|
||||
}
|
||||
article {
|
||||
float: none;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
<div class="toc">
|
||||
<%= self.html_TOC_rendered %>
|
||||
</div>
|
||||
|
||||
<article class="markdown-body">
|
||||
<%= self.html_rendered %>
|
||||
</article>
|
||||
<script src="js/code-prettify/loader/run_prettify.js?autoload=true&skin=sunburst&lang=css"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,6 @@
|
||||
## License
|
||||
This lab by [*Z. Cliffe Schreuders*](http://z.cliffe.schreuders.org) at Leeds Beckett University is licensed under a [*Creative Commons Attribution-ShareAlike 3.0 Unported License*](http://creativecommons.org/licenses/by-sa/3.0/deed.en_GB).
|
||||
|
||||
Included software source code is also licensed under the GNU General Public License, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||

|
||||
@@ -0,0 +1,47 @@
|
||||
## Introduction to managing identity and authentication across a network of computers
|
||||
|
||||
It is not unusual for an organisation's network to include a mix of many Unix and/or Windows computers. An organisation also often maintains a database of users or employees, with details such as email addresses and phone numbers. Many organisations prefer to have a system where users have user accounts centrally managed, so that users can log in to various systems using the same login details.
|
||||
|
||||
Due to the long history of technical solutions to these goals, there are many ways these can be achieved. Each solution has security and usability advantages and disadvantages.
|
||||
|
||||
In this lab you will implement centralised network-based authentication using LDAP, and you will investigate the security consequences. To save time, you will be making use of automated/graphical configuration tools, although if you end up specialising in this in the future, you will want to familiarise yourself further with the command line tools and relevant configuration files.
|
||||
|
||||
## Introducing Lightweight Directory Access Protocol (LDAP)
|
||||
|
||||
Lightweight Directory Access Protocol (LDAP) is a network protocol for accessing a hierarchical (tree-structured) database of information over TCP/IP. Technically, LDAP is not the term for the database, but the protocol that is used to talk to one; in practice LDAP server software tend to implement a database. Typically an organisation would use LDAP to share "phonebook" information about employees, such as their email addresses, job titles, office numbers, and so on. LDAP can also be used to centrally store credentials, so that people can use the same username and password on any computer that authenticates against the LDAP server. Other common uses includes configuration of DNS, DHCP, and email servers.
|
||||
|
||||
By default LDAP uses TCP port and UDP port 389. LDAP commands include searching, adding, modifying or deleting entries in the database. LDAP is a binary protocol (meaning it does not send ASCII human-readable instructions), and is by default not encrypted (information is plain text), which means that an eavesdropper (using a sniffer such as Wireshark) can view any information sent via LDAP.
|
||||
|
||||
LDAP has since been updated to include encryption add-ons, such as Transport Layer Security (TLS)/SSL, and can also be tunnelled through SSH. Note that some LDAP clients do not check the server's domain, but only provide encryption (meaning MITM attacks may be possible).
|
||||
|
||||
LDAP has some access control features, so that a client may be restricted to certain operations or data.
|
||||
|
||||
## Storing and retrieving in LDAP
|
||||
|
||||
The hierarchy (tree) of information stored via LDAP is known as the *directory information tree* (DIT). The structure of the database is defined via a *schema*. For example, a schema may define the fact that the database stores information about people, and what kinds of data is valid.
|
||||
|
||||
The root (main) node is commonly a set of "**dc**" values, which is short for *domainComponent*. For example, for leedsbeckett.ac.uk, "dc=leedsbeckett, dc=ac, dc=uk". In the database you created earlier, the dc="site".
|
||||
|
||||
Other common values are the "**ou**" or *organizationalUnit*, which defines the department within an organisation, such as "it" or "academic", and also the "**cn**" or "**sn**" (common name / surname) is used to describe the way an item is described, for example "Cliffe Schreuders" / "Schreuders".
|
||||
|
||||
A complete path that locates a node is a distinguished name (DN). For example, "cn=Cliffe Schreuders,ou=academic,dc=leedsbeckett,dc=ac,dc=uk" could be the DN for retrieving further information about that member of staff.
|
||||
|
||||
LDAP example database structure
|
||||
|
||||
## Using centralised network-based authentication via LDAP
|
||||
|
||||
Note that you have learned about *local authentication and user management*; for example, the use of /etc/passwd and /etc/shadow. However, in larger organisations it is often preferable to provide *network-based authentication and user management*.
|
||||
|
||||
*Centralised identity* schemes enable administrators to manage user accounts, which can be used to log into multiple networked systems within the organisation by using the same login details. This is the approach used by most medium to large organisations.
|
||||
|
||||
*Federated identity* is where user accounts from multiple organisations can be used in a connected way. For example, logging into Yahoo! with a Google account. *Single sign on (SSO)* is a related (but distinct) concept, where a user that has logged in to a service can access that service along with others, without having to log in again.
|
||||
|
||||
## Other network-based identity management solutions
|
||||
|
||||
LDAP is primarily a directory for storing and accessing information, and one use of LDAP is a central store of user account details. An older method of centrally storing account information is Network Information Service (NIS), which was created by Sun Microsystems. However, NIS has many security limitations (no encryption, verification, and password hashes are typically public). An enhanced version, NIS+, has been developed, but it is not very popular.
|
||||
|
||||
Kerberos is a network authentication protocol, which uses a trusted third party to enable clients and servers to verify each others identity, without sending passwords to each other directly. Tickets are distributed by a Key Distribution Center (KDC), which gives the authenticated client a time-limited access to the server.
|
||||
|
||||
Remote Authentication Dial In User Service (RADIUS) is a related protocol, which can also be used to manage authentication over a network, and is typically used to manage Wi-Fi connections and accounts.
|
||||
|
||||
Active Directory (AD) is Microsoft's amalgamation of LDAP and Kerberos. Windows computers are typically managed as part of a *domain*, which is implemented using a modified version of Kerberos for computers to authenticate and grant permissions to each other, and LDAP as a access protocol to retrieve information about accounts. Group policy automates specifying the security controls for Windows systems. Group policy is distributed to computers via AD automatically to any computers that are part of the same domain.
|
||||
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/ruby
|
||||
require_relative '../../../../../../lib/objects/local_hackerbot_config_generator.rb'
|
||||
|
||||
class HB < HackerbotConfigGenerator
|
||||
|
||||
attr_accessor :server_ip
|
||||
|
||||
def initialize
|
||||
super
|
||||
self.module_name = 'Hackerbot Config Generator'
|
||||
self.title = 'Lab'
|
||||
|
||||
self.local_dir = File.expand_path('../../',__FILE__)
|
||||
self.templates_path = "#{self.local_dir}/templates/"
|
||||
self.config_template_path = "#{self.local_dir}/templates/lab.xml.erb"
|
||||
self.html_template_path = "#{self.local_dir}/templates/labsheet.html.erb"
|
||||
|
||||
self.server_ip = []
|
||||
end
|
||||
|
||||
def get_options_array
|
||||
super + [['--server_ip', GetoptLong::REQUIRED_ARGUMENT]]
|
||||
end
|
||||
|
||||
def process_options(opt, arg)
|
||||
super
|
||||
case opt
|
||||
when '--server_ip'
|
||||
self.server_ip << arg;
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
HB.new.run
|
||||
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<generator xmlns="http://www.github/cliffe/SecGen/generator"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.github/cliffe/SecGen/generator">
|
||||
<name>Hackerbot config for an access control lab</name>
|
||||
<author>Z. Cliffe Schreuders</author>
|
||||
<module_license>GPLv3</module_license>
|
||||
<description>Generates a config file for a hackerbot for an integrity lab.
|
||||
Topics covered: .</description>
|
||||
|
||||
<type>hackerbot_config</type>
|
||||
<platform>linux</platform>
|
||||
|
||||
<read_fact>accounts</read_fact>
|
||||
<read_fact>flags</read_fact>
|
||||
<read_fact>root_password</read_fact>
|
||||
|
||||
<!--TODO: require input, such as accounts, or fail?-->
|
||||
|
||||
<default_input into="accounts">
|
||||
<generator type="account">
|
||||
<input into="username">
|
||||
<value>vagrant</value>
|
||||
</input>
|
||||
</generator>
|
||||
</default_input>
|
||||
|
||||
<default_input into="flags">
|
||||
<generator type="flag_generator"/>
|
||||
</default_input>
|
||||
|
||||
<default_input into="root_password">
|
||||
<value>puppet</value>
|
||||
</default_input>
|
||||
|
||||
<output_type>hackerbot</output_type>
|
||||
|
||||
</generator>
|
||||
@@ -0,0 +1,29 @@
|
||||
<html>
|
||||
<head>
|
||||
<title><%= self.title %></title>
|
||||
</head>
|
||||
<body>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="css/github-markdown.css">
|
||||
<style>
|
||||
.markdown-body {
|
||||
box-sizing: border-box;
|
||||
min-width: 200px;
|
||||
max-width: 980px;
|
||||
margin: 0 auto;
|
||||
padding: 45px;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.markdown-body {
|
||||
padding: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<article class="markdown-body">
|
||||
|
||||
<%= self.html_rendered %>
|
||||
|
||||
</article>
|
||||
<script src="js/code-prettify/loader/run_prettify.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,4 @@
|
||||
## License
|
||||
This lab by [*Z. Cliffe Schreuders*](http://z.cliffe.schreuders.org) at Leeds Beckett University is licensed under a [*Creative Commons Attribution-ShareAlike 3.0 Unported License*](http://creativecommons.org/licenses/by-sa/3.0/deed.en_GB).
|
||||
|
||||
Included software source code is also licensed under the GNU General Public License, either version 3 of the License, or (at your option) any later version.
|
||||
@@ -0,0 +1,43 @@
|
||||
## Linux Extended ACLs
|
||||
|
||||
We have explored standard Unix permissions. Modern Linux systems (and some other Unix-based systems) now have more complete (and complicated) ACL support.
|
||||
|
||||
As previously mentioned, an *access control list (ACL)* is attached to an object (resource) and lists all the subjects (users / active entities) that are allowed access, along with the kind of access that is authorised.
|
||||
|
||||
Set a file ACL on your mysecrets file, using the setfacl command:
|
||||
|
||||
```bash
|
||||
setfacl -m u:student:r ~/mysecrets
|
||||
```
|
||||
|
||||
This grants the "student" user read access to the file.
|
||||
|
||||
Note that the stat program is not usually ACL aware, so won't report anything out of the usual:
|
||||
|
||||
```bash
|
||||
stat ~/mysecrets
|
||||
```
|
||||
|
||||
The ls program can be used to detect File ACLs:
|
||||
|
||||
```bash
|
||||
ls -la ~/mysecrets
|
||||
```
|
||||
|
||||
`-rw-r-----+ 1 cliffe users 22 Feb 28 11:47 mysecrets`
|
||||
|
||||
Note that the output includes a `+`. This indicates an ACL is in place.
|
||||
|
||||
Use getfacl to display the permissions:
|
||||
|
||||
```bash
|
||||
getfacl ~/mysecrets
|
||||
```
|
||||
|
||||
Use Linux File ACLs to grant one or more specific users (other class members) read access to your mysecrets file.
|
||||
|
||||
Using ACLs, grant any other group (you choose) read-write access to your mygroupshare file.
|
||||
|
||||
Remove the group permission you just added.
|
||||
|
||||
> Example: `setfacl -x g:staff file`
|
||||
@@ -0,0 +1,34 @@
|
||||
# Access Controls: Set User ID (SUID)
|
||||
|
||||
## Getting started
|
||||
### VMs in this lab
|
||||
|
||||
==Start these VMs== (if you haven't already):
|
||||
- hackerbot_server (leave it running, you don't log into this)
|
||||
- desktop (you can sudo to get superuser access)
|
||||
- server (<%= $server_ip %>, you can ssh to this machine, but you don't have superuser access)
|
||||
|
||||
### Your login details for the "desktop" and "server" VMs
|
||||
User 1: <%= $main_user %>
|
||||
Password: tiaspbiqe2r (**t**his **i**s **a** **s**ecure **p**assword **b**ut **i**s **q**uite **e**asy **2** **r**emember)
|
||||
|
||||
User 2: <%= $second_user %>
|
||||
Password: <%= $second_password %>
|
||||
|
||||
|
||||
You won't login to the hackerbot_server, but the VM needs to be running to complete the lab.
|
||||
|
||||
### For marks in the module
|
||||
1. **You need to submit flags**. Note that the flags and the challenges in your VMs are different to other's in the class. Flags will be revealed to you as you complete challenges throughout the module. Flags look like this: ==flag{*somethingrandom*}==. Follow the link on the module page to submit your flags.
|
||||
2. **You need to document the work and your solutions in a Log Book**. This needs to include screenshots (including the flags) of how you solved each Hackerbot challenge and a writeup describing your solution to each challenge, and answering any "Log Book Questions". The Log Book will be submitted later in the semester.
|
||||
|
||||
## Meet Hackerbot!
|
||||

|
||||
|
||||
This exercise involves interacting with Hackerbot, a chatbot who will attack your system. If you satisfy Hackerbot by completing the challenges she will reveal flags to you.
|
||||
|
||||
> If Hackerbot seems to be waiting or halted, simply say 'hi'
|
||||
|
||||
Work through the below exercises, completing the Hackerbot challenges as noted.
|
||||
|
||||
---
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user