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!
CVE-2014-1314, not found by the authors, was a funny design flaw. When creating a CoreGraphics session, it will send a request to start a process under the user's context. However, user's can specify an arbitrary script to run upon login. So, this creates a process that is outside of the sandboxing. Neat!CFPropertyListCreateWithData API takes in Unicode strings, which was a good target for overwriting the memory we wanted. An additional win is that the randomization on large blocks of memory is very bad.IOAccelSurface interface used by Apple's Graphics Driver. It represents an area of a rectangle that will be rendered by the GPU. It appears to have been designed for WindowsServer to use but normal processes can also call it. Hence, it's likely a fairly software target. The article discusses the internal workings of this driver, which required a lot of reverse engineering to do.0x4000. By providing a value larger than this, the condition of y 16705, x 321, height -1, len -1 is possible to hit. Before bailing out, a single out of bounds write will occur.IOUserClient objects pointer. The goal was to corrupt this to point to data that the attacker controls on the heap. Getting this object in the proper spot via feng shui is discussed as well, and it's worth a read!hd (hosted domain) and email. The application would verify both of these claims to be correct before logging in.sub field could be used for this but it's inherently unreliable on Google OAuth for some reason.container_of macro to do this a lot. According to the author, this technically violates the C language standard and is always an unsafe cast. The goal was to find cases where the casting into the container (child) type is incorrect, leading to a type confusion bug they call container confusion.container_of in the source code to create a type system. This tracks all casts up and down. From there, they built a custom sanitizer called uncontained in order to detect casts up then back down to the wrong type./tmp. Ruby has a framework called Bootsnap that allows for loading Ruby/Rails Apps faster via caching. Much of the configuration and cache for Bootsnap is stored within /tmp/cache/bootsnap.load-path-cache contained gem file paths in to the MessagePack format. Additionally, comiple-cache-* contained compiled Ruby, JSON and YAML. From there, they decided to review the source code of Bootsnap to get an idea of what made sense to corrupt.config/boot.rb.require, Bootsnap checks the cache first./tmp/restart.txt. The arbitrary file write can be used to write to this file a second time to trigger the RCE bug.successfulMessages mapping prevents the same withdrawal from being executed more than once.0xDEAD. The variable is xDomainMsgSender. On a cross-chain message, this is set to the calling user. In effect, this acts as a reentrancy protection as well. At the end of the call, the storage value is set back to the default.initialize() instead of using reinitializer modifier. Such a small line of code seems so simple. So, what's wrong?0xDEAD at all times except during the withdrawal process. Within the initialization code (which gets retriggered), this value is set to 0xDEAD but actually defaults to zero. Normally, this would be fine (since it should be a NOP) but that's NOT true in the context of the withdrawal code!failedMessages mapping.
0xDEAD.
relayMessage passing in the withdrawal request. This will succeed because the DEFAULT 0xDEAD address was set back.
xDomainMsgSender global variable doesn't seem important until you have the better context of what it does and why it's important. It's crazy how this reentrancy/replay protection was touched by this simple upgrade code. What an awesome find!keep[index] that actually perform the access. The author compares this bug to reviewing JIT compilers. They try to enforce invariants early on in the program then the rest of the code assumes that this invariant is true. If the invariant is ever violated, then you have a memory corruption bug.