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!

Superfluid Post Mortem Hack- 1053

Superfluid    Reference →Posted 3 Years Ago
  • Superfluid.sol allows for composable Superfluid agreements in a single transaction. I have no idea what this means (lolz). The important thing to note is that the main contract and the agreements have a concept of context (ctx).
  • The ctx is a serialized state for through the entire transaction for different agreement calls. This context includes information about the original msg.sender even.
  • The convention of callAgreement is to use a placeholder ctx so that Solidity can read it directly from the argument ctx that should be there.
  • The flow of operations is like so for verifying:
    1. Call deleteAnyFlowBad.
    2. Call callAgreement. This creates the ctx and puts a stamp on it.
    3. Call createFlow to verify that the calling host contract is authorized to do so.
    4. Call authorizeTokenAccess to hand over the ctx and deserialize the original call.
  • The vulnerability occurs in the parsing of the ctx structure within the function deleteAnyFlowBad. After everything is merged into a single byte array. The expected empty ctx can contain spoofed data, causing a MAJOR problem to occur. Since the abi decoder ignores the legit ctx, we have now tricked the code into parsing the wrong ctx.
  • With the ability to craft an arbitrary ctx, the calldata can be crafted to impersonate other users. This can be used to create IDA indexes on behalf of other users to steal tokens in their possession.
  • The contracts had been previous audits by several users and Peckshield. They have decided to add a bug bounty program and get more audits in the future. Overall, a super interesting bug in extremely complicated code.

Exploiting CVE-2022-42703- 1052

Seth Jenkins - Project Zero    Reference →Posted 3 Years Ago
  • The bug report CVE-2022-42703 by Jann Horn is a use after free on struct anon_vma in the memory management (MM) subsystem of the Linux kernel.
  • The vulnerability is extremely complex and particular to the subsystem. From reading the bug report, there appears to be an incorrect assumption made on reference counting for VMA objects that trickles down into other portions of code. This bad logic leads to a use after free.
  • By triggering the vulnerability above, the object folio->mapping can get a dangling reference to a anon_vma object. By calling madvise(..., MADV_PAGEOUT), the access on anon_vma can be repeated in the free state.
  • Within the structure, are several pointers. The route the author decided to go down for exploitation was to fill this with addresses and corrupt them. The function down_read_trylock() would corrupt the memory at a chosen address after some primitive hunting.
  • To get this to work though, we need to be able to supply our fake structure. Since anon_vma belongs to its own kmalloc cache, it's not simple to free and reclaim. The author points to a known technique to free all of the objects in the slab page, flush the percpu freelist and cause the virtual memory to get sent back to the regular allocator. With a spray, we can control this.
  • The arbitrary write had constraints on the write that would occur. It would increment the value by 0x100 if the 3 least significant bits and most significant bit were set. In the future, the value will be decremented back down, meaning that this has some limitations. We also don't know the KASLR slide, making this even harder.
  • On x86_64 Linux, when the CPU performs interrupts and exceptions, it will swap a respective stack that is mapped to static and non-randomized virtual addresses. This has been exploited in the past in order to exploit something to not need knowledge of the KASLR slide.
  • What's the game plan then? Force an interrupt to occur. Once this happens, we can use our arbitrary write to corrupt the registers in the stack frame in the kernel context. The author choose to interupt a call to copy_user since the data is controllable and there is a length value in a consistent register (RCX) that we can overwrite.
  • It turns out, that there is an interrupt for hardware breakpoints that is easy to trigger. So, the author wrote code to trigger this exploit method:
    1. Setup two processes: X and Y. Y is the original and X will ptrace Y.
    2. Set a hardware breakpoint at a known address in Y.
    3. Make a large number of uname requests. This is because copy_to_user is throughout.
    4. Trigger the breakpoint in the code for Y. This causes the location to be saved for the codes stack frame.
    5. Slightly after the frame is saved, use the UAF to write to process Y's stack frames saved length value.
  • The technique above works for reading out too much data. For reading a stack buffer to userland, this can be used to defeat the KASLR slide and stack cookies. If the technique is inverted, it can be used to write too many byes to the kernel as well. The target of this was prctl to create a stack overflow where none existed in the past.
  • Since the read leaks the stack cookie and KASLR slide, it is trivial to bypass both mitigations! Now, we can start a ROP chain. To mitigate this, they suggested randomizing these areas of memory. They do note that the mitigation doesn't work for local users (only remote) since a TLB timing side-channel can be used still.
  • Overall, interesting technique on Linux exploitation. It's cool to see such a powerful primitive discovered that can be used in other locations.

Disclosing information with a side-channel in Django- 1051

Dennis Brinkrolf - Sonar Source    Reference →Posted 3 Years Ago
  • Django is an open source Python framework used for web applications. It is used by many organizations as the backend web server for a website.
  • Django is an MVC (model view controller) framework. It has a templating engine to allow for simple integration between the different sections of code - Django Templating Language (DTL).
  • The author gives a simple example: showing registered users of a database with some control over the fields being sorted on, such as starting letter or something else. The Python code returns a list of objects for the context of the template. The template runs {% for e in users|dictsort:sort % to iterate through all of the usernames in a filtered way.
  • What's the problem? It's an issue with the resolution process of the sort itself. Under the hood, dictsort uses the built in function sorted with a custom function to decide the order. The sort attempts to exclude all sensitive values in the object (__ by convention).
  • Django has done a wonderful job to prevent access to unauthorized things. What's the problem? The lookup attempts 4 different ways for searching: dictionary lookup, attribute lookup (class), list-index lookup and method call without arguments. The FINAL option allows us to call arbitrary functions without parameters. According to the author, they claim this could be used to delete application files or any bad things.
  • Instead of showing this route, they take it another way: a sorting oracle. The idea is that since we fully control the sorting key, we can learn information about the service. For instance, if we sort based upon the first character of the password, we can learn if a password is ABOVE or BELOW our password. Nice! :)
  • With full control over the data in the database for a given password, this could be used to extract a ton of sensitive information. In Django, passwords are hashed with an unknown secret and a random salt though. How is this possible then? First, a trick: if two values are the same, then it will always be the same order - the unsorted form.
  • With the unsorted form at hand, users can be put into groups. If a column has a particular character ('a') then it will be put first or 'b' be put second. What if two column characters are the same? We will know this since we KNOW the unsorted order of the column! This allows for the discerning of the end of one group and the start of another.
  • The key to this scheme is the unsorted items to understand the ending of a group. This requires a character to be EXACTLY the same in every single group. Another assumption that is made is that every character is represented. Given enough entries (like a password hash) this is likely though.
  • The attack has many requirements but allows for the extraction of sensitive data via a side channel of sorting. To fix this vulnerability, the maintainers restricted the ability of _proper_resolver to remove list and function invocation. Overall, amazing post on a crazy side channel!

Cool vulns don't live long - Netgear and Pwn2Own - 1050

Kevin Denis - SynAckTiv    Reference →Posted 3 Years Ago
  • Pwn2Own is a competition focused on finding vulnerabilities in high value targets. In this rendition of Pwn2Own for IoT devices, they choose the Netgear Router RAX30. Pwn2Own has many tough issues:
    • Bugs must be in the most recent version of the firmware. Although this seems obvious, this means a patch the day before may change the exploit pattern.
    • You can only enter once per device and duplicates don't get payouts. This means that an awesome bug may have been found by somebody else.
  • While looking at the binaries, puhttpsniff caught their eye. Using the strings command shows some HTTP parsing, which is always interesting. The binary inserts NFLOG iptable rules to run callbacks.
  • While reviewing the command, there is a super trivial command injection vulnerability when constructing IP tables with the User Agent header. The exploit payload is curl --user-agent "a\";/sbin/reboot;\"" http://192.168.1.1. This was on the LAN side.
  • With access to the devices while running via the previous bug, they started hunting for more. By listing socket information, they learned that SSH and telnet are open for IPv4 and IPv6 on the LAN. When running nmap on the device from the WAN on IPv4 (default), nothing comes up though.
  • However, from our learnings from earlier, the device is listening on IPv6 as well. This is because the the IP table rules for IPv6 are only applied to the LAN interface and the WAN if a public IPv6 address is provided. If a link-local address is used on the WAN interface (same network segment), all of the services are accessible. Pretty neat bug!
  • With a bypass for accessing restricted services, what else can we do? /etc/shadow has a hardcoded password that was easily cracked via John the Ripper. Now, the telnet port can be used to connect. Additionally, the telnet prompt had hardcoded commands but had a special bad door sh to escape this.
  • The full steps for the second chain are as follows:
    1. Ping the address of the WAN interface. This can be used to find the link-local address of the device. I don't fully understand IPv6 networking so I'm pretty much copying and pasting here.
    2. Launch telnet with the cracked credentials.
    3. sh command to escape the shell.
    4. Since the user with the cracked password has uid 0, we are now root.
  • This was a very novel vulnerability in the routing tables; I will definitely keep this in mind for future assessments. Sadly, both the networking bug and command injection were fixed a few days before the event. So so so sad. Regardless, amazing findings!

Cacti: Unauthenticated Remote Code Execution- 1049

Stefan Schiller - Sonar Source    Reference →Posted 3 Years Ago
  • Cacti is an open source monitoring solution used by many different companies. They found this initially by scanning for bugs with their tool.
  • The application is written in PHP. At the very beginning of the app, an authorization check is performed. If the IP address corresponds to a hostname in a table, then it will allow the user to make the request. Otherwise, it will deny it.
  • While trying to figure out the IP, many user controlled headers are able to influence this request. A plethora of headers like HTTP_X_FORWARDED can be used to control the IP. Since the IP is used by authentication purposes, this is a complete authentication bypass.
  • Using their tool, there appeared to be a command injection vulnerability within the user provided poller_id parameter for the bad sync proc_open. This creates a fairly trivial command injection vulnerability that can be used to get code execution.
  • The first mitigation was to make the headers being accepted configurable but off by default. This is helpful for situations where this is behind a reverse proxy. For the command injection, cacti_escapeshellarg was used on the variable in two separate places to prevent a regression from occurring.
  • Overall, their tool seems impressive! They keep reporting high impact issues like this one. Secondly, trusting headers that are user controlled for sensitive operations is a common problem. Good find!

RCE via SSTI on Spring Boot Error Page with Akamai WAF Bypass- 1048

pmnh & Dark9T    Reference →Posted 3 Years Ago
  • Spring Boot has a pretty famous issue: when data is reflected within an error message, the Exception message uses Spring Expression Language (SpEL). For instance, $(7*7) will render 49. The authors of this post found an outdated version of Spring Boot being used which had a parameter reflected in an error message. Simple, right?
  • The SpEL language is a templating language that can be used within Spring. When having an injection via server-side rendering, this can be used to execute Java methods, construct objects and other data to eventually get code execution. For information on SSTI in SpEL, spel-injection is a good link.
  • Once they discover the SSTI, they try to try the simple payload ${T(java.lang.Runtime)}. This is a SpEL shorthand for referencing a Java class by name. However, the Akamai WAF blocked this request, even though they knew it was vulnerable. Now, we must learn why this was blocked by the WAF and how to work around it, which took over 500 requests to do.
  • With Java-based code injection vulnerabilities, the first issue is finding out how to load arbitrary classes. 1${2.class} will output java.lang.Integer. To create an arbitrary class, the author tried 1${2.class.forName("java.lang.String")} which was rejected based upon the function forName.
  • They needed to be able to create a string. The most straight forward route to RCE is .exec() is why. Reading the Java documentation (which is usually amazing), gave them the function toString() to get a non-static reference to a character. With this, they could use a toString() on an integer to return the proper character in a string they needed. Progress!
  • With the ability to create arbitrary strings, we're getting closer. With a string at hand, we need to find a way to call java.lang.Runtime.exec. They used a known technique as follows:
    • Use reflection (introspection feature) to get access to the Class.forName function to get an arbitrary package.
    • Build a String with the value java.lang.Runtime to pass to the function.
    • Use reflection to get access to the getRuntime function.
    • Build a string for exec using the crazy method above.
    • Call exec with our string.
  • A GET request has a limitation of 2kb. Since each character was 45 bytes long, this limited us to 45 characters in our payload. They tried to find an optimization, but couldn't find one after hours of trying. Eventually, they settled for a small payload in the exec function.
  • After hours of grinding, a simple uname -a response could be seen! The bug had been exploited and the WAF bypassed. To me, the interesting part of the article isn't the bypass itself but the thoughts around bypassing the WAF and problem solving.

Reverse engineering my cable modem and turning it into an SDR- 1047

stdw    Reference →Posted 3 Years Ago
  • The author had an old cable modem sitting in their closet. While browsing some forums, they learned that the device had a built in spectrum analyzer for diagnostics. So, they wondered, if a cable modem and TV tuner do the same thing, then can this be turned into an SDR? Let's find out!
  • To initially gain access, they setup a UART console. This gave them a wealth of information, such as the OS and processor being used. However, upon booting the serial console is disabled. The only interesting thing is going into the bootloader prompt to load a new image or read/write to memory locations directly.
  • The bootloader is a good target but cannot be done blindly. Upon looking at the board, they learned that all persistent storage was on a single SPI flash chip. Can we dump this? The winbond 25Q32JV yields a datasheet with pinouts and is supported by flashrom!
  • We have a problem though: dumping a SPI flash chip requires power. If we give the board power, the chip will be used, preventing us from reading out the data we want. The solution? Remove the VCC board by carefully lifting its pin from the pad. The author also did this with the chip select (CS) line, since it's common for it to be wired to VCC as always on.
  • To connect to the chip, the author wires up to all of the pins on the chip. Additionally, they put a jumper wire onto the pads without legs and connect the leg to the jumper whenever they want to boot normally. Now, by using flashrom and a Raspberry Pi, the image can be completely dumped. They even have the commands they ran!
  • What's in the image? The author could see some credentials but that was at. Luckily, the tool bcm2-utils has the capability to dump, parse and modify configuration files from Broadcom cable modems. They modify the images configuration to turn on the serial console and have a simple telnet password. Neat!
  • They boot back into the device with serial and are greeted with a nice eCos console to pop a root shell. While there, they couldn't find any commands to turn on the spectrum analyzer so they started reversing the code of the OS in Ghidra. So many interesting quirks from reversing! Like, the call command can be used to call any code at any location.
  • While reversing, they came across the code to enable the bandpower measurement for a given frequency range in the eCos console. The code indicated that the analyzer just changed a few memory mapped registers, indicating that it was just at a slightly higher power. When they read this memory location, they as raw IQ data!
  • They wrote some magic scripts to trigger the code that was mentioned above. They put the registers to look at particular ranges, making this into an SDR. Parsing FM radio signals from possible via some code they wrote. Mission accomplished!
  • Overall, awesome article on reverse engineering. Some of the tricks, such as lifting the legs off the chip. Good write up!

Asus M25 NAS Vulnerability- 1046

One Key    Reference →Posted 3 Years Ago
  • One Key has recently created an automated scanner for scripting languages and compiled binaries. To start with, they support Python and PHP scripting languages with various bug classes, such as command injection, path traversal and many others.
  • This analysis tool led to the discovery of 15 critical bugs in 6 different vendors. All of these will be fixed besides an Asus NAS bug since it's been EOL'ed. It seems they gave the tool the firmware of the device and it was able to magically discover bugs. Pretty neat!
  • While parsing cookies, the code exec("cookie_user -c ".$_COOKIE['CookieID'])); is ran. This is used to execute PHP code dynamically. Since the string CookieID is controlled by us, this can be used inject our own code into the program.
  • Overall, the bug they found is pretty simple. It's neat that the tool is able to tear apart firmware and find these sorts of bugs in the code. This could be a good tool for security researchers looking for quick bugs or vendors as a check prior to launching their product.

Checkmk: Remote Code Execution by Chaining Multiple Bugs (3/3)- 1045

Stefan Schiller - Sonar Source    Reference →Posted 3 Years Ago
  • This is the final part of the series. In the first two posts, an SSRF, LQL query injection leads to an arbitrary file deletion. This leads to a complete authentication bypass by racing a file for auth. In part 3, we finish off the chain.
  • The endpoint CoreModGeneral contains a arbitrary file read vulnerability. A URL can be passed in but does not validate the URI type. This means an attacker can pass in the file:// scheme and retrieve arbitrary files from the system.
  • CheckMk has two types of users: normal and automation. The automation user is pre-configured with a random secret, which is stored in plaintext via the file automation.secret. By using the arbitrary file read from above, we can escalate privileges to read the credentials and login as this user.
  • In terms out that the automation user is quite restricted so we want to be a normal user. How does it know the difference between an automation and a regular user? By checking for the existence of the automation.secret file! So, once we read the file, we can use a previous vulnerability to delete the file, making us appear as a regular user. Now we are a normal user!
  • For the seamless authentication for Nagvis to take place, dynamic PHP code is generated. In particular, user information is put into a string in real PHP code. Single quotes within this data are escaped by prepending a backslash. However, if the data contains a backslash itself, we can escape the attempted escaped single quote. For instance, the input A\' would become A\\' instead of A\\\', allowing us to escape the context.
  • The bug above gives us an authenticated code injection vulnerability. From a single SSRF to authentication to code execution is pretty amazing. This is probably the most amount of bugs I've ever seen chained together. More interestingly, some of these quirks weren't bugs - the functionality, such as the file deletion in this step, was just an implementation quirk. Awesome write up!

Checkmk: Remote Code Execution by Chaining Multiple Bugs (2/3)- 1044

Stefan Schiller - Sonar Source    Reference →Posted 3 Years Ago
  • This post is part 2 of a chain of bugs that lead to getting code execution. In part 1, a SSRF and line feed injection bug in a query language were found. However, the LQL injection is blind.
  • In SQL, a strategy to get around this limitation is using conditionals and sleeping when a condition is met. In LQL, this can be done via the WaitObject, WaitCondition and WaitTimeout headers. Using this, it is possible to use the blind injection to retrieve arbitrary data. Although, this data is not very sensitive.
  • LQL contains a COMMAND option, which allows for Nagios External Commands. Even though this sounds promising, many of the sensitive commands were disabled for security reasons in Nagios already.
  • However, they found the command PROCESS_FILE. Issuing this command directs Nagios to read the file, execute each line of the file and exits. If the second parameter of the command is non-zero, it will delete the file being processed. This gives us an arbitrary file deletion primitive.
  • How does is this primitive useful for us? It's all context dependent. Am authentication cookie contains the SHA256 hash of a username, session id, serial number and the secret of the server. This secret is stored in the file auth.secret. When performing authentication if the secret is not known, it will reload the file with 256 random characters.
  • This is where things get WILD! There is another application that uses the auth.secret file: NagVis. This is done in a seamless fashion by verifying the session cookie but doesn't do any proper validation on whether the file is empty or not but the main process does.
  • So, here's the attack:
    1. Use the arbitrary file deletion to delete the secret storage file.
    2. Get the main process to create the file BUT not save the secret. This leaves the secret empty.
    3. Use the other PHP component to use the empty file in this small time window.
  • This attempt takes a few tries but eventually works. Since we can generate our own cookies now, we have created a complete auth bypass. Pretty neat!