Resources

People often ask me "How did you learn how to hack?" The answer: by reading. This page is a collection of the blog posts and other articles that I have accumulated over the years of my journey. Enjoy!

Documenting Sony Memory Stick- 809

Dmitry Grinberg    Reference →Posted 3 Years Ago
  • The piece of hardware being reverse engineering is the Sony Memory Stick. A few use cases include Aibo Robot Dogs, Magic Gate DRM and GPS devices. The whole purpose of this project was to simply preserve and understand history. For reverse engineer, there are 10 pins on the stick, with pin outs available at pinouts.ru.
  • To start the reverse engineering, they analyzed an old Sony CLIE PDA. From looking at the wiring the author knew this was a simple 1-bit transform mode. To make his life easier, PalmOS 4 binaries were built with almost all function names still intact and 68k is an easy to reverse engineer architecture. The author took a look at the interface with a logic analyzer to come to some results.
  • To send information about ready a 0xAA or 0x55 was sent on the line. If the given phase is over, it will toggle to the last bit of the phase to indicate it was done. The 1-bit mode had three wires: BS wire for bus signal state, CLK for the host to send the card a clock signal and SDI0 for the bidirectional data. In 4-bit mode, SDI0 become SDI0, SDI1, SDI2 & SDI3. Data lines are pulled down, the clock idles low and data is set on the rising clock edge.
  • When sending a transaction (TPC), the TPC is made up of 8 bits, where the first 4 bits are the inverse are the final 4 bits for determining errors. The top-most bit holds the operation: read or write. The data is always followed by a 16-bit CRC with with an initial value of 0 and a polynomial of 0x8005. The flow of information is as follows and is similar between host to card and card to host:
    1. BS line goes high.
    2. A bit with no meaning is sent to wait for everything to sync up properly.
    3. 4 bits of a TPC are sent followed by the next 4 bits that are inverted. The FINAL bit is inverted with the BS line going low in order to indicate a phase change for the data mode.
    4. Receive the data. The length is pre-configured.
    5. CRC is sent. The least significant bit of the CRC has its bit flipped and the BS line goes high in order to indicate a phase change.
    6. Send the data over the SDIO line and a CLK over the CLCK line.
  • There are several registers for configuring modes, accessible memory and other things. From reverse engineering the binaries, the author figured out what all of these registers means, including the type of stick being accessed and the INT register for showing errors. The commands and registers are completely different from the PRO and the original version of this.
  • The commands for the memory stick are raw NAND flash commands with a few extra steps. The NAND must handle flipped bits by using error correcting codes (ECC) and handle blocks that are no longer good with wear leveling. To allow blocks to go bad, 3.1255 of the devices raw capability are hidden for the remapping of blocks with wear.
  • When a Memory Stick is inserted, it must be mounted. The per-device management is stored within the Boot Block and the Backup Boot block, which are written at the factory. Both of these are marked as special sections in the out of band (OOB) and the block itself. The information in these structures pertains to memory mapping, sizes and many other things. To mount (after verification of everything), a mapping of physical to logical is made to read the OOB properly with the block faults and everything else.
  • To read from a logical sector, we need to divide the number by the logical block number. The remainder of this is the page within the sector. Using the table to convert from logical blocks to physical blocks, we can find the physical block number. Once we find this, we read the page (from the previous math) of this block. The write is fairly similar; none of them do block relocations when an error occurs.
  • The author wanted to see the MSIO (misc I/O) on the memory sticks as well. To find the functions associated with this, he wrote a value in the register category. If data can be read back, then it's a valid handler. Neat trick to figure out how things work! Every device that used this interface did it in a completely different way, making the reverse engineering even more fun to deal with.
  • The Pro had an entirely different set of commands and register information. The author claims it is easier to deal with, since more sane choices were made for it. Interesting article (as always from this guy) on reverse engineering complicated things!

BrokenPrint: A Netgear stack overflow- 808

Alex Plaskett - NCC Group    Reference →Posted 4 Years Ago
  • ReadySHARE is a feature of Netgear router feature that is used connecting to a printer via USB as if it were a network printer. When a printer is plugged into the router, this feature is automatically turned on for the router.
  • The router takes in a connection on port 631 by creating a new thread. This accepts a HTTP-like request (but made from scratch with very little validation. The code snippets in this are quite large and Hex Rays dumps, making them not so easy to read.
  • While parsing the content of the body, the contents of our request are copied into a stack buffer via a memcpy. Since we control BOTH the size of the overflow and the bytes with no character restrictions, this is a pretty awesome bug to exploit.
  • In terms of binary protections, there is no stack canary, Nx is turned on, no PIE (.bss and .text randomness), no RELRO and ASLR is partially enabled. The libraries and stack are randomized but the heap is not. Additionally, the location of the overflow is at the address furthest away from the return pointer. As a result, we are going to have to craft a set of fake objects in order to allow for our exploit to happen.
  • The first thing they did was find a path that hit the least amount of possible things. In particular, they escaped the while loop that the buffer overflow occurred in by editing the index value to be
  • They decided to create a leak primitive in order to be able to reference pointers and call specific functions in LibC. In order to do this, they found a pointer and a size they could overwrite that would return data over the socket to them. However, along the way, they overwrote a socket fd. So, they brute forced the socket fd between different runs.
  • The final road block was that the pointer would be freed prior to returning the data. This meant that they could only leak data information that was on a valid heap pointer. For whatever reason, a few spots in the Global Offset Table (GOT) in the .bss section wouldn't crash on this but they never investigated why. They could have just gotten their leak from the heap as well, especially considering the heap was not randomized.
  • With the LibC address in hand, they could calculate the address of system. We still need a place to reference a string and we do not have a stack leak. So, they used a known trick with 32-bit and mmap not being randomized so well. By making a large enough allocation in LibC, it creates an mmap call directly, making it trivial to find our string.
  • From there, they create a ROP chain to call system with our string placed in the mmaped chunk. To pop a shell, they used the command "nvram set http_passwd=nccgroup && sleep 4 && utelnetd -d -i br0" to backdoor the device. Now, The password is reset and we can take full control of the router.
  • I really enjoyed this article since it showed the messiness of hacking and making things work. There are a few interesting tricks in here as well, making it all the more enjoyable!

Beej's Guide to Network Programming- 807

Beej Jorgensen    Reference →Posted 4 Years Ago
  • Socket programming is hard. This is a VERY comprehensive page on sockets and how to use them. Just saving this resource for later :)

Heap Overflow in OpenBSD's slaacd via Router Advertisement - 806

Quarkslab    Reference →Posted 4 Years Ago
  • slaacd is a stateless address auto configuration (SLAAC) daemon. In the IPv6 protocol stack, the Neighbor Discovery (ND) protocol is used for gathering information about network communications, gateways and many other things. One particular type is a Router Advertisement (RA) packet. This particular bug is an OpenBSD.
  • One of the many options in RA is a DNS Search List Option. This contains one to many domain names of DNS suffixes. Domain names included in this format are encoded with a sequence of labels, which each have a corresponding length byte.
  • While processing this data, the length byte is improperly used as a signed value instead of an unsigned value. By crafting a length that has the most significant bit set to 1, it believes that it is a negative number instead of a large positive number.
  • This vulnerability breaks the sanity checks within the code. In particular, it tries to ensure that the length of a single entry does not exceed 63 bytes. But, since our length is negative, this sanity check is not triggered, which eventually leads us to a memcpy.
  • When the size goes to the memcpy, the signed integer is transparently turned into an unsigned integer. This leads to a huge write occurring within this memory space, ending up as a heap overflow. Since this is a bad size wildcopy, it is unlikely to be exploitable.
  • Regardless of the exploitation viability, the author wrote a script in Python using Scapy for networking.S capy is a Python program that enables the user to send, sniff and dissect and forge network packets. By having access to data at this low of a level in the stack, the author was able to trigger the bug for a crash.

The Discovery and Exploitation of CVE-2022-25636- 805

Nick Gregory    Reference →Posted 4 Years Ago
  • One night, the author of this post decided to look at the netfilter subsystem of the Linux kernel. Netfilter enables packet filtering, NAT translation, packet logging and many other things. In particular, they chose to review the protocol parsers for two reasons. First, protocol parsing of non-trivial data tends to be error prone. Secondly, the configuration input came from userland with good control.
  • While digging through the source code of this functionality, they ran across the following line:
    entry = &flow->rule->action.entries[ctx->num_actions++];
    
    This line caught their eye because it was incrementing ctx->num_actions and using it as an index without any bounds checks. Secondly, the struct flow->rule->action.entries had seemingly not obvious relationship with ctx->num_actions. Not a bug yet but a code smell that prompted for more review!
  • How do we determine if an overflow of some sort is occurring here? The hacker asked themselves what is the length of the action.entries array, what are the controls on this function and how are things initialized? All great questions to get to the point of figuring out if this is a bug or not. While diving into this, they found that the path for how things were called. Additionally, they found that the num_actions counter is ONLY incremented when the NFT_OFFLOAD_F_ACTION flag is set on the offload flags.
  • When reviewing the code that called this functionality, none of them were setting NFT_OFFLOAD_F_ACTION. The problem is that the actions array is allocated based on the number of immediate expressions types and does NOT take into consideration that this index could be incremented. As a result, the MAX index would be different than the original allocation size.
  • Finding a supposed vulnerability in the Linux kernel and trigger it are two different things. The author had to learn how to trigger the code for nftables. After playing around with the CLI for a while, they noticed it was adding arbitrary restrictions, which screwed up his exploitation attempts. Because of this, they use the GoLang implementation with custom overwrites. After playing with binary settings and tracing code, they were able to trigger the bug with a kernel panic. Exploitation time :)
  • When starting to hit exploitation, it is crucial to know what the bug provides. The dereference code above gave as an entry struct to play with. In particular, the fields id and dev were being written. To find the offsets of these structs, they used pahole. The id field writes a value of 4 or 5; dev was writing a pointer 24 bytes past the end of the array.
  • The size of the allocation depending on the amount of immediate rules that were inside of the filter. With no rules, it was 32 bytes; with one rule it's 112 and two rules it is 192. The allocation location is important, since it changes the heap (slab) location that is used. While hunting for target objects in this slab, they hit a road block, since no good targets were around.
  • After going through this post on a recent kernel bug, they realized something: this bug can be triggered multiple times! This allows hitting different offsets as a result and chain multiple objects together. The post by Alexander Popov uses the security pointer of msg_msg at offset 40 (which is hittable offset by us) to land an arbitrary kfree.
  • Using the security pointer inside of msg_msg as a target, it will eventually be freed. Since the write will have our net_device pointer (dev in the code above), we have manufactured a use after free from this. In order to make this viable, a ton of heap spraying was done to get tihs to line up JUST right for the attack.
  • Once the free has occurred, the goal is to get this heap chunk back to overwrite information within the field. In particular, we can set the net_device.netdev_ops function pointer to get code execution in the kernel when this object is overlapped. The exploit chain above has a few nice quirks:
    • The overwritten pointer for list_head.prev inside of the msg_msg can be FOUND by calling MSG_CPY. This allows us to know which one is corrupted.
    • Besides being able to tell if it's corrupted or not, it contains a kernel heap pointer for us!
    • Checking the /code> of a security pointer tells us WHICH one was corrupted with the ID value from above. Boom, code execution!
  • The exploit was the opposite of consistent though; they kept getting crashes and had no idea why. They hypothesize it had to do with freelist randomization or the other sporadic allocations within the 128 slab (they tried to rewrite this in a different slab even). This was working 30% of the time, but they never figured out what was making it fail. The exploit code is on Github.
  • Overall, a super interesting post about the bug discovery, primitive gathering and exploitation strategizing. I absolutely LOVE Nick's blog posts since they show the nitty-gritty details of finding and exploiting bugs in the Linux kernel. Good work!

7 RCE and DoS vulnerabilities Found in ClickHouse DBMS- 804

Uriya Yavnieli and Or Peles - JFrog    Reference →Posted 4 Years Ago
  • ClickHouse is a Database Management System (DBMS) for online analytical processing. This is a web analytics tool used for seeing what is going on with a database.
  • When sending a request to the server, compression can be used. On the server side, it will decompress the file according to the header that was sent. The struct used for this has a few fields: hash type, compress method, compressed size (without checksum), decompressed size and the actual compressed bytes. The client supplies the entire struct to the server and thus controls all of its contents.
  • The size of the allocation made for this is from the decompressed_size field. When the copy actually happened, this size value is not used though! Instead, the data within the buffer is used instead. This creates a fairly standard buffer overflow.
  • As a proof of concept, they set the size to be 1 and sent over a large payload that was much bigger than this. There is some magic that goes into the size of the actual data being proper, but they do not explain it. Eventually, this segfaults with control over an indirect call (function pointer). Sick! There is the same bug in a similar location that is not covered in the post.
  • When doing the decompression, a 16-bit user supplied offset is read in from the compressed_data field. This is then subtracted from the current pointer location. There is NO validation that the offset is smaller than the real pointer being used. Down the road, a copy is done, leading to an out of bounds read. A similar variant of this bug exists but is going forward on the offset instead of backwards.
  • I assume that the offset specified above is for pagination or something similar. Additionally, they found a divide by zero bug which simply crashes the application.

Another vulnerability in the LPC55S69 ROM- 803

Laura Abbott - Oxide    Reference →Posted 4 Years Ago
  • Oxide is building a computer completely from scratch. Before blindly using something, they have decided to completely understand everything on a chip before using it. While developing a product for the LPC55S69, they found undocumented code last year that led to a huge security problem. They are back at it again with these bugs!
  • The In-System Programming (ISP) interface is used for a signed firmware update mechanism that exists on the ROM. This is for updating the firmware of the chip itself in the case that a critical security issue was found on the chip. Doing this securely requires perfect code and proper cryptography.
  • The ISP interface receives data in the SB2 format. This format includes a header followed by a set of commands to modify the flash or start code execution. To ensure confidentiality and integrity, the update commands are encrypted with a key set at the manufacturing line.
  • The update itself is parsed as groups of 16-byte blocks, where different parts of the update are referenced by this block number. The SB2 parser copies the entire ROM into a global buffer before checking the signature. However, instead of just grabbing the header information for this (128 bytes), it uses the field m_keyBlobBlock. If this variable is harder than 128, then a buffer global memory buffer overflow occurs.
  • In practice, this causes major security issues. By using this buffer overflow, code execution is possible until reboot of the chip. However, since we now control the flash update mechanism, this can be used to modify flash contents, ignoring the signature verification altogether. The POC mentioned in the article enables SWD mode on the chip in order to allow for debugging the existing ROM, which should not be possible.
  • There are some mitigating factors though. First, if the system is secured with secure boot and sealed via the Customer Manufacturing Programming Area (CMPA), modification of the code in flash will be detected on boots in the future. I was also thinking that if the commands must be encrypted, then can this code even be hit?
  • Overall, another really interesting finding within the NXP chip by Oxide! This seems like a super cool product and company to work for.

System environment variables leak Browsers - CVE-2022-0337- 802

Maciej Pulikowski    Reference →Posted 4 Years Ago
  • In the land of Windows, the usage of %ENV_VAR% can be used to reference environmental variables. Commonly, this is used within CMD as developers.
  • When saving a file, the name of the saved file can be returned. This is expected and useful functionality within the web. However, saving a file with the name as an environmental variable had some weird functionality.
  • In particular, if a file was saved with an environmental variable name, such as %username%, it would return the value of the environmental variable! It is common for developers to store secret information, such as AWS_SECRET_ACCESS_KEY, Github secrets and many other things. As a result, this attack could be used to steal sensitive information from a device.
  • How would you get a user to save a file with an environmental variable as a name? Using the window.showSaveFilePicker function, a malicious website can specify the suggstedName field for the file.
  • But, would a user save a file with this name? The attack that the author came up with is super cool! They make a site that says "Hold Enter For 2 Seconds". While holding enter the Save File screen comes up, which will auto focus onto Save File screen. Now, the save button will be triggered, with only a flash on the screen.
  • This bug is only applicable on Windows but effects Chrome, Edge and Opera. Although the usage of the ENV variable in the file name does not seem like a big deal, the attack method of the auto focus made this feasible. I would bet this could be used somewhere else in the future for similar attacks that require user interaction

cr8escape: New Vulnerability in CRI-O Container Engine - 801

John Walker & Manoj Ahuje - CrowdStrike    Reference →Posted 4 Years Ago
  • CRI-O is an implementation of the Kubernetes Container Runtime interface. It is a lightweight altnerative to using Docker with Kubernetes.
  • The CRI-O interface uses the pinns utility to set kernel options for a pod. Recently, pinns added support for sysctl. Pinns will blindly add kernel parameters, including sysctl without any validation. This is an interesting primitive: can we do anything with this?
  • The sysctl flag kernel.core_pattern can be used for how the kernel should react to a core dump. In this case, we will set this to a script that we control within our container to be triggered. Since this needs to be an absolute path, we also need to find the full path of the script. This can be done via the mount command.
  • It does appear that this is not the standard type of container escape where an attacker has code execution within the context of a box. Instead, they need to be able to specify parameters within the YAML file for the initialization of the pod. Although this is cool, it is not as impactful as it could be, since control over the pod settings is required.

Dirty Pipe Vulnerability - 800

Max Kellermann     Reference →Posted 4 Years Ago
  • The author of this article is not a security researcher; they are a software developer. They found this vulnerability in the Linux kernel while trying to track down a software bug. In particular, a CRC at the end of a file kept getting corrupted and they couldn't figure out why. The corruption just kept on happening and they HAD to get to the bottom of it.
  • The corruption was happening within the CRC of a log file. The functionality works like this:
    1. Web service writes a ZIP header.
    2. Splice is used to send all compressed files. This syscall is used for copying data between one file to another in kernel space, which helps with I/O performance.
    3. write is called to write the directory file header. This is 50 4b 01 02 1e 03 14 00. This is EXACTLY the corruption that is happening.
  • After debugging this for a while, they came to the conclusion that this MUST be a kernel bug. They wrote up a quick proof of concept to demonstrate the bug; this was composed of two progams running simultanously. The first program was writing data to a file, acting as the the log splitter. The second program was running splice followed by a call to write, simulating the zip generator. Even though the write was NOT occuring on the call to splice, the string from the second write appeared to be in the file being read. Specifically, this problem existed in pipes.
  • The Linux kernels smallest unit of memory managed by the CPU is a page (4kB). If an application requests memory from the kernel, it will get a number of pages; all I/O happens with pages. For instance, if you read in a file, the kernel wil first copy a number of 4kB chunks form the hard disk into kernel memory called a page cache. A pipe is a unidirectional file descriptor used for inter-process communication. One end is for pushing (writing) data, while the other end of it pulls the data.
  • When using a pipe, a reference to a page cache entry is made via the data structure pipe_buffer. These objects have a reference to the backing memory page and have several flags for what permissions and things are allowed. The main bug is that the flags for this are NOT initialized when using pipes. In Linux 5.8, the flag PIPE_BUF_FLAG_CAN_MERGE was added, which indicates whether a page table is mergable or not. Practically, a poisoned set of flags, namely PIPE_BUF_FLAG_CAN_MERGE, allows data to be written to a page cache that the pipe does not own!
  • This can facilitate the ability to write and change the file data in the page cache even if it’s opened as read-only, giving a privilege escalation primitive. The data is never written to disk unless the page cache entry is considered dirty. Since the accidental write does not mark the page cache as dirty, the write to disk will never occur on disk; it will only happen in the cache. As a result, the file can be changed in memory, but never be written to disk, making this a real sly attack.
  • To exploit this vulnerability, the following steps need to happen:
    1. Create a pipe.
    2. Fill the pipe with arbitrary data. We want to set the PIPE_BUF_FLAG_CAN_MERGE flag in ALL of the entries.
    3. Drain the pipe (remove).
    4. Splice the data on the target file that is opened read only, just before the target offset that we want to overwrite.
    5. Write data into the pipe. This data will overwrite the cache file page instead of the data in the proepr buffer.
  • The author has a final note on this bug: "To make this vulnerability more interesting, it not only works without write permissions, it also works with immutable files, on read-only btrfs snapshots and on read-only mounts (including CD-ROM mounts). That is because the page cache is always writable (by the kernel), and writing to a pipe never checks any permissions."
  • To me, it's pretty crazy how the lack of initialization of a value caused such major problems. Even in the Linux kernel security hardened memory management system, there are security vulnerabilities. DayZeroSec has a good synopsis on this vulnerability as well.