CSAW Finals - Grande
I recently played CSAW CTF 2021 with PPP. I worked with Anish on a cool challenge, grande, by @itszn13. This was an Express node application which exposed some interesting behavior about Express’s query parsing.
Overview
There were two steps in the challenge.
The first was a XSS. This required creating an array-like object for which Array.isArray(obj) === false
, which can be done with ?next[__proto__]=first&next[__proto__]=second
.
The second was a CSP bypass. In summary, the nonce got set to undefined
when the nonce
cookie is unset but the user session was not null. We could then abuse logout CSRF to force this condition, due to the SameSite
properties of the cookies.
5 RCEs in npm for $15,000
I found and reported these vulnerabilities with @ginkoid.
In this post, I will discuss the root cause of these vulnerabilities, as well as briefly walk through the exploitation process. I’ll also include some thoughts about bug bounty in general at the end.
These are the associated CVEs and payouts:
- CVE-2021-32804 ($10,000)
- CVE-2021-32803 ($2,000)
- CVE-2021-37701 ($2,500)
- CVE-2021-37712 (found internally - $1,000 token payout)
- CVE-2021-37713 (found internally)
- CVE-2021-39134 (TBD)
CVE-2021-39134 affects @npmcli/arborist. The others affect node-tar.
Empires and Deserts
This is an author writeup for the paired Chrome sandbox escape I made for redpwnCTF 2021, Empires
and Deserts
.
When writing this challenge, I wanted to create a sandbox escape where the solution is not obvious. In other words, the difficulty of the challenge arises not from exploiting the vulnerability - but in finding the vulnerability itself.
SBX Intro
Lately, I’ve been getting into Chrome sandbox exploitation. Having found and exploited a few sandbox escape vulnerabilities, I thought it would be fun to include these in a CTF. Unfortunately, one issue I faced while learning SBX is lack of online resources.
I think conceptually, this attack surface is not exceedingly complex - at least compared to the renderer. In this blog post, I aim to provide a high level overview of SBX concepts, which will hopefully speed along the learning process.
Breaking GitHub Private Pages for $35k
I found and reported this vulnerability with @ginkoid.
This was actually the first report that paid out for me on HackerOne. At $35,000, it’s also the highest bounty I’ve received so far from HackerOne (and I believe the highest GitHub has paid out to date).
A lot of bugs seem to be a mix of both luck and intuition. In this blog post, I’ll illustrate my thought processes in approaching such a target.
ASUS RT-AC68U RCE
Over the summer of my junior year, I decided to do some router pentesting. Embedded security always seemed very fun to me. I liked the idea of breaking things that are found in our everyday lives, and what better place to start than my router. I was also inspired by my friend @arinerron who had some success with his router previously.
I dumped the firmware and started analyzing the binaries in Ghidra. I also found a GitHub repository containing a modified version of the source which greatly helped with the reversing process.
College Applications
This is a bit of a departure from the norm on this blog. I thought it might be interesting to switch it up a bit, and talk about my experience with the American college application process. This is in part inspired by my friend @arinerron’s post on school sponsored extracurriculars.
I think college applications have quite a lot of symbolic value. They’re the culmination of a twelve-year scholastic journey, a period in our sentence to pre-collegiate learning. Their finality is perhaps best exemplified by the seasonal afflictions of “senioritis”. After submitting applications, students have a tradition of slacking on classwork.
Of course, I too am afflicted. A testament to the fact that in the end, college applications underlie much of our scholastic life.
Adult CSP
This is an author writeup for Adult CSP, a Chromium sandbox escape that I wrote for DiceCTF 2021.
Overview
I wanted to write a pseudo-realistic Chromium sandbox escape. In particular, this meant no helper functions to give leaks.
There were a total of two intended vulnerabilities:
- UAF on
Cat*
for leaks - UAF on
CATServiceImpl*
for controlled vcall
Interestingly enough, both of these showed up in one line of code.
base::PostTask(
FROM_HERE, {content::BrowserThread::UI},
base::BindOnce(&CATServiceImpl::ProcessCATOnUI, base::Unretained(this), base::Unretained(it->second.get()), std::move(callback))
);
base::Unretained
means that it is the caller’s responsibility to ensure the object lives past the call. Usually these should be replaced with weak pointers, unless it’s obvious that it’s impossible for the object to be destructed before the function call - for example, an owned child member.
These show up pretty commonly as real Chrome vulnerabilities too, making it quite suitable for a CTF challenge.
Shattered
This was a very interesting challenge.
Analysis
The libc version is 2.29. This implies the use of tcache bins, as well as additional protections against double-free.
As usual, the first thing we do is run checksec
.
$ checksec shattered
[*] '/home/robert/writeups/binexp/hsctf20/shattered/shattered'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
All protections enabled - it’s a typical heap exploit challenge. Then again, this is to be expected. The challenge author, poortho
, is notorious for only writing glibc heap problems.
The exploit path will probably involve getting a libc leak, and then overwriting one of the hooks - __malloc_hook
or __free_hook
.
SSD November
I recently won the SSD November challenge, the challenge itself was actually quite interesting.
The first vulnerability was improper hashing.
while (i < size) {
tmp_value._0_1_ = input[i];
if ((int)(char)tmp_value * 10 < 0x20) {
tmp_value._0_1_ = (char)tmp_value % '\x05';
}
else {
tmp_value._0_1_ = (char)(((int)(char)tmp_value * 0x124343) % 0xef);
}
input[i] = (char)tmp_value;
i = i + 1;
}
Upon seeing this, I was immediately suspicious. Most hash functions, even handrolled ones, have both addition and multiplication? I didn’t really understand what was going on, but analysis through GDB showed that the values tended towards very high values (ie 0xfc, 0xfd, 0xfe, 0xff, 0x00).
Because the hash is done per character, I handpicked a few characters with distinct hash values after running them through the max repetition of hashes. From here, we can easily brute force the 4 byte long admin password.
dmzf
The week before early admission deadline, perfect time to do a CTF and burn a weekend.
Analysis
Libc version is 2.27, we get tcache without the security checks.
As usual, the first thing we do is run checksec
.
[+] checksec for '/home/robert/writeups/binexp/meta20/dmzf/dmzf'
Canary : ✓
NX : ✓
PIE : ✓
Fortify : ✘
RelRO : Full
Canary, NX, PIE, Full RelRO - it’s a typical heap exploit challenge. The exploit path will probably involve getting a libc leak, and then overwriting one of the hooks - __malloc_hook
or __free_hook
.
There’s also seccomp which makes exploitation a bit more tricky.
House Of Red
House of Red
This is an author writeup for house-of-red
and its sibling problem zero-the-hero
, both of which appeared in the 2020 redpwnCTF. Their respective challenge repositories are also open sourced.
This writeup presents a relatively novel exploitation technique, that can be applied to a wide range of challenges.
Implications
There are two prerequisites to execute this attack.
- Libc address leak
- Constrained write in libc
The most common scenario for the second constraint is mallocing a chunk, and then providing a negative size value. If we are able to perform such a write, we can almost always overwrite some part of _IO_2_1_stdin_
to escalate to shell. A similar attack scenario appeared in justCTF 2019’s ATM Service. Although FSOP wasn’t the intended scenario, the relative overwrite in libc allowed me to bypass the buffer overflow.
Tiktok
This was one of the more interesting challenges I’ve done in a while. We were one of 4 teams who solved this binary exploitation challenge in DawgCTF.
Analysis
This was the only challenge where we were given a libc. Looks like it’s going to be a heap pwn.
As usual, the first thing we do is look at the protections on the binary.
$ checksec tiktok
[*] '/home/robert/writeups/binexp/umbccd/tiktok/tiktok'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
All protections are enabled except for PIE, implying that we’ll probably have to use either FSOP or write to one of the malloc hooks to win.
Dumping the binary into Ghidra, I immediately noted something suspicious. The fd
is stored but never validated again after creation.
read(songs[choice].fd,songs[choice].lyrics,(ulong)size);
Null byte overwrites are really common, especially when dealing with off by one errors or C string functions. If we could somehow overwrite the fd
to null, we could control the heap!
babyllvm
I recently competed in Codegate CTF 2020 under the junior category. This was the one of the more interesting challenges that I solved.
Summary
This was more of a reversing problem than pwn. The llvm served only to obfuscated the code, as opposed to raising any challenges itself.
Analysis
Three observations are needed to solve the problem.
- The data pointer can be out of bounds after a codeblock finishes executing.
- During branched execution, the security checks don’t ever get called. 3.
- During linear execution, ptrBoundCheck won’t get called if you don’t adjust rel_pos.
Tasteless CTF 2019
I competed in Tasteless CTF this weekend with redpwn. We solved one challenge, House of Bad Taste, which was an interesting glibc heap pwn.
House of Bad Taste
Flag
tctf{p01nt3r_c00k1e_b3st_c00ki3!}
Analysis
As usual, the first step is to run checksec against the binary.
$ checksec chall
[*] '/pwn/tasteless19/house-of-bad-taste/chall'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
$ strings libc.so.6 | grep GNU
GNU C Library (Ubuntu GLIBC 2.29-0ubuntu2) stable release version 2.29.
Compiled by GNU CC version 8.3.0.
With all protections enabled, it’ll probably be another heap exploit. GLIBC 2.29 means tcache protections are enabled.
The next step is to decompile the binary with Ghidra.
pico19 Secret Hitler
Analysis
The binary uses glibc version 2.29, which patches the double free vulnerability.
Solution
We are given the libc base address, so no leaks are needed. All we have to do is get a write.
House of Poortho
The vulnerability is that read() overwrites the first byte of the next chunk header with a null byte. If the next chunk has a size header with least significant byte not equal to 0x00, the size of the next chunk changes.
pico19 Sice Cream
Flag
flag{th3_r3al_questi0n_is_why_1s_libc_2.23_still_4_th1ng_62167e9e}
Analysis
$ strings libc.so.6 | grep GNU
GNU C Library (Ubuntu GLIBC 2.23-0ubuntu11) stable release version 2.23, by Roland McGrath et al.
Compiled by GNU CC version 5.4.0 20160609.
GNU Libidn by Simon Josefsson
$ checksec sice_cream
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
RUNPATH: './'
The libc version is 2.23, meaning that tcache has not been implemented yet. We could also try House of Orange because of less strict checks. Only PIE is disabled, meaning that we will probably have to go for either FSOP or an overwrite on __malloc_hook
or __free_hook
.
Decompiling the binary with Ghidra, there are no checks on the pointer that we free, leading to a double free vulnerability. We also have the ability to print an array in .bss, name
. Finally, we get a total of 20 mallocs, with a constrained size (size < 0x58)
.
pico19 Ghost Diary
Flag
picoCTF{nu11_byt3_Gh05T_41a29ece}
Analysis
$ ldd ghostdiary
linux-vdso.so.1 (0x00007ffcabdd4000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff81dd18000)
/lib64/ld-linux-x86-64.so.2 (0x00007ff81e30c000)
$ strings /lib/x86_64-linux-gnu/libc.so.6 | grep GNU
GNU C Library (Ubuntu GLIBC 2.27-3ubuntu1) stable release version 2.27.
Compiled by GNU CC version 7.3.0.
$ checksec ghostdiary
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
The libc version is 2.27 which implies the use of tcache with very little security checks. All protections are enabled, implying a heap only exploit.
We can only malloc 20 chunks at a time (which is not a really big concern). There is also a rather interesting constraint on malloc size, (size <= 0xf0 || (size >= 0x110 && size <= 0x1e0)
. There is a null byte overflow in the edit function. In addition, we can print any chunk, regardless of if it’s freed or not, which we will use to get a libc leak.
CSAW Red 19 Tumbler
I was one of the two teams that solved Tumbler from CSAW Red.
Problem
Pwn 500
No way that cryptocurrency is a scam, that would NEVER happen
nc pwn.chal.csaw.io 1000
Analysis
The libc provided was 2.23.
$ strings libc.so.6 | grep GNU
GNU C Library (Ubuntu GLIBC 2.23-0ubuntu10) stable release version 2.23, by Roland McGrath et al.
Compiled by GNU CC version 5.4.0 20160609.
GNU Libidn by Simon Josefsson
Decompiling the binary, it is immediately apparent that we have an arbitrary write primitive in one of the later functions called.
void arb_write(void)
{
void *__buf;
puts("Which coin do you want to edit?");
__buf = (void *)get_number();
puts("What are you writing?");
read(0,__buf,0x100);
return;
}
Seating Charts
Creating a seating chart for a class is an extremely interesting problem that delves into the realms of both web design and competitive programming.
Overview
There are two questions I attempted to answer.
- How to create an easy to use interface that minimizes the cognitive load on the user
- How to best create the seating chart given a list of preferences for each student
Java Tricks
Honestly, you should switch to c++. But if you insist on using Java, here are some cool tricks.
Memory
Memory allocation is extremely cheap (~1e6 bytes per 1ms) compared to everything else - don’t be afraid to allocate huge arrays. That being said, be careful you don’t hit a MLE.
Be careful of the dimensional order of 2D arrays.
Secret Hitler Account Takeover
This is an account takeover attack I discovered on the open source Secret Hitler game.
By submitting crafted parameters to the /password-reset
endpoint, attackers are able to takeover arbitrary non-staff accounts.
This vulnerability can be mitigated by disabling JSON parsing.
We control all of the parameters passed through req.body
.
const { username, password, password2, tok } = req.body;
Secret Hitler Vulns
Two low-moderate vulnerabilites on the open source Secret Hitler game. Note that a lot of the vulnerabilites are due to the use of JSON parsing, which allows attackers to submit arbitrary objects to the endpoints.
Obfuscated IP Leakage
The check in the /profile
endpoint is unnecessarily complex, and forgets an edge case.
if (req && req.user && requestingUser && requestingUser !== 'undefined' && req.user.username && requestingUser !== req.user.username) {
// Error
}
pico18 jbr
Cryptography - 700
Problem Statement
Dr. Xernon has finally approved an update to James Brahm’s spy terminal. (Someone finally told them that ECB isn’t secure.) Fortunately, CBC mode is safe! Right? Connect with nc 2018shell1.picoctf.com 22666
.
source
Hint: What killed SSL3?
pico18 Dog or Frog
Misc - 900
Description
This is a classic machine learning problem.
We came across this article and copy much of the template code from there. I wrote my code in a Jupyter notebook.
tj18 Abyss
Written by nthistle
Problem Statement
If you stare into the abyss, the abyss stares back.
nc problem1.tjctf.org 8006
Observations
The first observation is that this is a Python environment.
However, further experimentation reveals that all our errors are eaten up with a cute message.
>>> blahblop
The Abyss consumed your error.