This commit is contained in:
Emlyn Butterfield
2019-07-09 10:50:20 +01:00
300 changed files with 10918 additions and 766 deletions

2
.gitignore vendored
View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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.)

View File

@@ -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

View File

@@ -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')

View File

@@ -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

View 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

View File

@@ -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}"

View File

@@ -0,0 +1,2 @@
secrets: \#MyWeirdSecret on twitter
https://twitter.com/hashtag/MYWEIRDSECRET?src=hash

View 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.

View File

@@ -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"%>"

View File

@@ -21,4 +21,5 @@
<reference>https://atlas.hashicorp.com/puppetlabs</reference>
<software_license>various</software_license>
</base>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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 +

View File

@@ -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>

View File

@@ -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.

View File

@@ -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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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.

View File

@@ -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*/

View File

@@ -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!
![small-right](images/skullandusb.svg)
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.
---

View File

@@ -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>

View File

@@ -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&amp;skin=sunburst&amp;lang=css"></script>
</body>
</html>

View File

@@ -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.
![small](images/leedsbeckett-logo.png)

View File

@@ -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)

View File

@@ -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`

View File

@@ -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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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.

View File

@@ -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!
![small-right](images/skullandusb.svg)
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.
---

View File

@@ -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>

View File

@@ -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&amp;skin=sunburst&amp;lang=css"></script>
</body>
</html>

View File

@@ -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.
![small](images/leedsbeckett-logo.png)

View File

@@ -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 roots 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 roots 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 wont 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?==

View File

@@ -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>

View File

@@ -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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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>

View File

@@ -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&amp;skin=sunburst&amp;lang=css"></script>
</body>
</html>

View File

@@ -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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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.

View File

@@ -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" &gt; \~/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
```

View File

@@ -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!
![small-right](images/skullandusb.svg)
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.
---

View File

@@ -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>

View File

@@ -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&amp;skin=sunburst&amp;lang=css"></script>
</body>
</html>

View File

@@ -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.
![small](images/leedsbeckett-logo.png)

View File

@@ -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&amp;Security%20-%20The%20State%20of%20the%20Art%20of%20Application%20Restrictions%20and%20Sandboxes%20-%20Author%20Version.pdf)

View File

@@ -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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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.

View File

@@ -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.==

View File

@@ -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!
![small-right](images/skullandusb.svg)
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.
---

View File

@@ -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>

View File

@@ -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&amp;skin=sunburst&amp;lang=css"></script>
</body>
</html>

View File

@@ -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.
![small](images/leedsbeckett-logo.png)

View File

@@ -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)

View File

@@ -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`

View File

@@ -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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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.

View File

@@ -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!
![small-right](images/skullandusb.svg)
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.
---

View File

@@ -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>

View File

@@ -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&amp;skin=sunburst&amp;lang=css"></script>
</body>
</html>

View File

@@ -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.
![small](images/leedsbeckett-logo.png)

View File

@@ -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.

View File

@@ -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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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.

View File

@@ -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`

View 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!
![small-right](images/skullandusb.svg)
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