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!
src attribute is used for the location of the page. Placing a javascript: URI can lead to XSS here and in forms and anchor tags. data: URIs here the code can be executed but it's executed on the null origin. To prevent attacks on the URLs, a developer can restrict the domain to only contain http/s: in it. Still, redirects can be made from the page. focus, blur and postMessage. There are also readable properties like frames, top, opener, parent and others. Additionally, the location.href property is writable. srcdoc attribute as well. It's similar to the src but the iFrame will take in data for the doc and share the same origin as the original page. These can be HTML encoded as much as you want as well.sandbox property which is off by default. If just "sandbox" is used then all protections are on but can also have explicit protections turned on. There are several flags that change how the upper layer can be redirected. There are some function related ones, like allow-downloads. allow-popups allows window.open() to be called in order to open new pages, but this page is still sandboxed. Adding allow-modals allows for the escaping of the sandbox on calls with a null origin. allow-popups-to-escape-sandbox will remove the sandbox on popped windows.allow-same-origin will set the origin to non-null it will keep the original origin of the call instead of a unique origin with separate cookies. allow-scripts allows JavaScript to be executed within the frame. There is also a CSP sandbox attribute for the iFrame as well.window.open has three parameters. URL is the obvious one. The second one is the name of the window. If there already is a window with the same name as provided then it will provide a reference to the other one named this way. window.open. user_thread is torn down - this frees the socket and user structures. However, the rdp_client_thread still has a pointer to this object! So, if a message is sent to close the audio channel, this is accessing a freed pointer! This creates a classic use after free vulnerability.strdup() with a size of 0x90. But, this is limited to zero nullbytes, making it infeasible. So, now what?input_thread allocated with arena4 was the best thing for controlling the data within for our UAF. lock_handler() function pointer is called on an argument provided by itself. Since the data after the function pointer gets corrupted, they use a pivot gadget before proceeding. Once done, they called system with their provided parameter to pop a shell. Pretty neat!fillRelay() and the dataworker will handle it.deposit and fill. The deposit is what the relayer does and the fill is what the dataworker does, after something has happened to the initial fill. Being able to tie a fill to a deposit is important to ensuring that double spends don't occur - both for the on chain and off chain infrastructure.validateFillForDeposit Fill() filters all recent fills to find the proper deposit for it. getValidUnfilledAmountForDDeposit() obtains the previous fills for the deposit against depositsWithBlockNumbers(). Additionally, there is a function that handles updates() that were being made to the transfer.relayerFeePct field would be updated for a sped up deposit within the local object. Since the hash of the original object and the new object were different, it saw that as a valid fill! The tying together portion of the code has been broken.relayerFeePct on the source chain. This will get the relayer to see the deposit to NOT see it as a slow relay anymore.relayerFeePct. Personally, I don't like the client side fix very much; I feel like doing something with the hash would make more sense. Unfortunately, there are times where hashing too many things is just as bad as hashing too few.mint() the amount of tokens paid is rounded down. If the tax was 1%, then sending in 99 tokens would result in 0 tokens, instead of 1, being sent in. unstake() there's a calculation error that allows a user to bypass the lock duration. There's a weighted average function for unstaking. It takes into consideration the total unstaked tokens and the amount of tokens newly being unstaked. Given this information, it will return a time where the tokens can be unstaked.currentUnstakedTokens is 201600 larger than newUnstakedTokens. When this happens, the newLockedUntil function will return the previous time! Using the same strategy as before, an attacker can unstake small batches of tokens at a time to avoid the locking period.scheduleBatch() can be used. Overall, interesting hack for 20M!VGAState struct of VirtualBox there is a bitmap used for tracking dirty pages of a VRAM buffer. This bitmap is large enough to use the maximum vram allowed by vbox at 256MB. When clearing the dirty bits, the start_addr is incorrectly multiplied by 4! If the address is larger than 64MB, then leads to an out of bounds access.VGAState, there is a section called CritSect. This is a critical section that can only be used by one thread at a time for in and out instructions for each devices MMIO region. The cLockers variable is effectively a locking variable to ensure that other threads don't access it at the same time. By abusing a bit clear, it could be possible to create an artificial race condition here.RTCRITSECT_FLAGS_NOP determines whether locking operations are checked at all, which controls the check above. The idea is to use the original exploitation path to change the flag BEFORE the crash happens. Then, after that, we can continue using the race condition for other things.vbe_ioport_write_data can be used once again to corrupt the size of the buffer cScratchRegion. With the size corrupted, it creates an easy out of bounds read and write. VGAState variable is PDMPCIDEV. Since this is part of the initial allocation, it's always in the same spot! It contains several function pointers, leading to easy code execution. Even with CFG turned on it doesn't matter because we control the pointer and two of the parameters being passed in.innerHTML was being set. Johan Carlsson was approached about needing a CSP bypass on Github.com for this XSS in order to make it exploitable. Using things like autofilling credentials with a form didn't even work because the form-action was being set or css due to a strict allowlist. turbo-frame. By adding in a form with turbo-frame in it, Rails will listen for the inserted element and grab it from the backend dynamically for us. Since it was grabbed in a legit fashion, it also grabs the CSRF token.turbo-streams an attacker can modify the input forms with a click anywhere on the page and submit the form. The impact of passing CSRF protections is that an attacker can call any form-based request, such as add SSH keys.focusOrLoadElement, it's possible to force the page to click the various buttons for us.hash. This has been documented for a long time but was not something that I knew about.window.open on the target window in order to do this. The post I linked above from WellCaffeinated does this by simply setting the frame source.opcode with a length and value, then arguments after the opcode. When initially connecting to a server, the select instruction is used. Most values are taken from a database but the image type is directly controlled by a connecting attacker.LENGTH field is not the bytelength but the codepoint length for UTF8. Since UTF8 implementations differ and we have two locations parsing the characters (Java and C), there is likely to be a bug here. The article has a good descriptor on what they mean by this - Technological Variety. length() of the object in Java compared to C. Sending in a 4 byte UTF8 character sequence was interpreted as a 2 byte sequence in Java. Why?length() function returns the number of Unicode code units instead of code points. Weird! connect instruction, we can control the host that an attacker connects to. This can be used to leverage data, such as credentials. Or, RDP drive redirection can be enabled to leak world-readable files on the server._next/image component is a built in image optimiziation library that is enabled by default. This works by making a request to the endpoint _next/image under the hood, which implements caching. Now, the actual server makes a request to //localhost/duck.jpg with the provided URL. There is a remotePatterns configuration that restricts the protocols and hostnames set, which is commonly set to '*'.https://example.com/_next/image?url=https://localhost:2345/api/v1/x&w=256&q=75. Most of the time, this is a blind GET request but there was situations where the impact can be escalated. First, with an old version of NextJS or dangerouslyAllowSVG is set then this SSRF leads to an XSS via the image reflection on the domain. If the response doesn't have a Content-Type then the full response is leaked.Host header to make the request. So, by providing the Host header, it's possible to force a localhost redirect leading to SSRF.HEAD request return a 200 with a specific content-type to satisfy the constraints of the system.