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!
MiraclePtr instead of standard pointers. The algorithm works just like reference counting under the hood for each pointer. PartitionAlloc allocator will quarantine the memory region before releasing it. Additionally, they set the pointer with garbage memory so that a UAF would not be very useful.browse_website and other functions along these ideas. One idea would be to force a sponsored result to return tainted data that could act as malicious input to the system.requests to eval a script from the internet. Auto-GPT saw a security issue with this so they used some misdirection with curl to trick the program to thinking that the usage of eval was safe in this case. This level of code execution was within Auto-GPT though.write_to_file and execute_shell were easy to do. There is a catch though: many of these commands require a confirmation from the user. docker-compose.yml) mounts itself into the container. Because of this, an attacker can write to this in order to escape the container on the next call. There is an additional setup where the python code is executed within a clean docker container with no issues. However, execute_python_code has a directory traversal vulnerability that allows for the modification of python scripts from outside the directory.getAum() function. This multiplies the pool amount by the price of the token from an external oracle to get the amount of received tokens.buyUSDP(), there is a function to increase the price of USDP and increase the pool amount. Within the removal process, there is no decrease price though. The flaw is that the calculations are not 1 to 1 between adding and removing assets. The call gives a 1 to 1.9 ratio, which is way to easy to make money from.purchasePLP(); about 1 Million from the original amount. Under the hood, this will buy USDP and mint PLP with a 1 to 1 ratio. Finally, it stakes this for the user.buyUSDP() with the rest of the funds. The problem is that the exchange rate has gone up between USDP and PLP, even though nothing has really changed.sellUSDP() to sell all of the staked amount. totalSupply is modified by a call to burn() but there is an external call prior to updating the reserves. reserves. Since the external call exists, an attacker could leave the contract in a state where the supply and reserve do not match. This results in the oracle inflating the price of the asset. I personally do not understand why being in this state benefits the attacker and I cannot seem to find code from Eraland. So, just going to take their word for it.XMM registers. Recent CPUs have increased these from 128-bits to 512 bits. 256 bit registers are called YMM and 512 bit registers are called ZMM. Besides number crunching, these are used in many libc calls for string based operations because of their speed and parallelism. strlen()
vpxor xmm0,xmm0,xmm0 ... vpcmpeqb ymm1,ymm0,YMMWORD PTR [rdi] vpmovmskb eax,ymm1 ... tzcnt eax,eax vzeroupper ret
YMM0 to zero XORing it by itself. The next instruction is using a pointer to our string in $RDI to check which byes match YMM0 and stores the result in YMM1. This is essentially checking if null bytes will match. The vpmovmskb instruction allows us to transfer this to the general purpose register eax. tzcnt finds the amount of trailing zero bits. With 4 instructions, we have successfully found the position of the first null byte of a string!vzeroupper. This is used to zero out the upper bits of the vector registers, which is important for performance reasons. A process has a special location for storing the state of these various registers: Register File and a Register Allocation Table (RAT). The RAT keeps track of what space in the register file is assigned to each register. For instance, when zeroing out an XMM register, the 'z-bit' flag is set in the RAT. So, vzeroupper just sets this flag to release the resources.vzeroupper does not revert the changes made to the z-bit in the case of branch misprediction. In a way, this creates a use-after-free-like scenario where a RAT mapping has been removed but will still be used after the revert of the state.strlen and strcmp use these instructions. So, we can target a string with these vector registers. To exploit the bug, a few steps must be taken:
cvtsi2sd instruction. vmovdqa instruction.vzeroupper branch prediction. This is a standard thing to force conditional branches to mispredict for speculative execution bugs.sfence in order to ensure they had full control of what was being executed._airdrop(). The code takes in three parameters:
from, to and amount. balance call with the amount provided by amount in the function.pairContract used for a pool. By setting this to 1 and calling sync() the pools price is very messed up, leading to an opportunity to make money.CurveHandlerV3() to see if the pool had interacted with ETH. The check was made by seeing if it was 0xeee...ee, which is a standard for ETH address. However, in reality, this used the WETH address. dlopen() and dlclose() on /usr/lib* on the main workstation. A local privilege escalation by Jann Horn would load a library from /tmp was discovered in 2016. This resulted in an allowlist being made to filter out types. Initially, they looked for a filter bypass or a directory traversal to this fix but couldn't find one.dlopen/dlclose primitive. Is this even exploitable? To determine this, they reviewed various default libraries that could be loaded.SIGSEVG signal handler and do not deregister that handler if closed. This turns into a use-after-free-like situation. 9 were found. mmaped section of memory that gets unmapped, reload code into that area, trigger the signal handler jump to executable stack for code execution. All of this sounds fine and dandy, but finding a proper path for this is tricky. So, the authors fuzzed the process with the various primitives from above. They injected their own signal handler with shellcode on the stack (0xCC opcode) to say if their shellcode as properly hit or not. They added their shellcode by writing to the socket of the connection directly.... overflowed sigaltstack. Sigaltstack allows a thread to define a new alternate signal stack for execution of signal handlers. Similar to the previous bug, the library was implementing a separate signal stack but not unregistering it. Once the signal was hit, improper code was being hit, creating a sigaltstack use-after-free. Although they found some primitives, they couldn't take this to code execution after loads of testing.RET N. Once this occurs, the signal handler restoration process occurs, overwriting the userland addresses back to normal. In order to exploit this, they needed an ASLR leak to jump back to the proper location. They did not pursue this option further.libunwind.so is loaded is several locations. Some other libraries load libgcc_s.so for handling C++ exceptions. If both of these are loaded and an exception occurs, LLVM's _Unwind_GetCFA will be called within libgcc_s.so instead of the LLVM library! These have different types of structures, leading to a super bizarre type confusion vulnerability.