Episode 58: In this episode of Critical Thinking - Bug Bounty Podcast we finally sit down with Youssef Samouda and grill him on his various techniques for finding and exploiting client-side bugs and postMessage vulnerabilities. He shares some crazy stories about race conditions, exploiting hash change events, and leveraging scroll to text fragments.
Follow us on twitter at: @ctbbpodcast
We're new to this podcasting thing, so feel free to send us any feedback here: info@criticalthinkingpodcast.io
Shoutout to YTCracker for the awesome intro music!
------ Links ------
Follow your hosts Rhynorater & Teknogeek on twitter:
https://twitter.com/0xteknogeek
https://twitter.com/rhynorater
------ Ways to Support CTBBPodcast ------
Sign up for Caido using the referral code CTBBPODCAST for a 10% discount.
Hop on the CTBB Discord at https://ctbb.show/discord!
We also do Discord subs at $25, $10, $5 - premium subscribers get access to private masterclasses, exploits, tools, scripts, un-redacted bug reports, etc.
Today’s Guest: https://twitter.com/samm0uda?lang=en
Resources:
Client-side race conditions with postMessage:
Transferable Objects
https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Transferable_objects
Every known way to get references to windows, in javascript:
https://bluepnume.medium.com/every-known-way-to-get-references-to-windows-in-javascript-223778bede2d
Youssef’s interview with BBRE
https://www.youtube.com/watch?v=MXH1HqTFNm0
Timestamps:
(00:00:00) Introduction
(00:04:27) Client-side race conditions with postMessage
(00:18:12) On Hash Change Events and Scroll To Text Fragments
(00:32:00) Finding, documenting, and reporting complex bugs
(00:37:32) PostMessage Methodology
(00:45:05) Youssef's Vuln Story
(00:53:42) Where and how to look for ATO vulns
(01:05:21) MessagePort
(01:14:37) Window frame relationships
(01:20:24) Recon and JS monitoring
(01:37:03) Client-side routing
(01:48:05) MITMProxy
Joel (00:00.338) Alrighty, Youssef, dude, you're probably one of our top requested guests that we get on the pod, so thanks for coming on and welcome. Hi, thanks for having me. Of course. I really enjoy your podcast and your show. Awesome, dude, that's great. So yeah, just for context for the viewers, we are here in sunny Miami. Joel (02:13.448) for H1305 and we're getting to do a live interview with Yusef Samouda. Am I pronouncing that right? Yeah, it's Samouda, but it's a nice good thing. Samouda. I tried. Oh, there's some construction going on or something. But yeah, dude, super excited to have you. So many people have requested, and your blog is absolutely legendary. So definitely looking forward to this one. I wanted to start us off with this episode with kind of discussing, obviously client-side stuff is your passion, you know? One of the things you love the most if we look at your write-ups that you've done on your blog. And so I kind of wanna, get a little bit more niche down inside of that and understand that a little bit more. What kind of client-side things makes your pulse go up? What kind of things? Are you talking post messages? Are we talking about hash? What kind of things within client-side stuff is your favorite to work with? Joel (03:17.454) I view it, of course, initially as a bounty hunter. So I look for stuff that pays off the best. So maybe I look to anything related to oath. So eventually I can escalate to have an ATO. So it would be maybe post message, maybe a like leaking the hash with the token or token. Yeah, so. That makes sense. There's definitely a lot of areas of client-side stuff where that sort of stuff comes into play, and if you look at your blog, it's just an array of, okay, we've got a hash leak, we've got a post message, but we got XSS, we got everything all over the place. But for you, it's mostly focused on, let me see what this application does, and let me see how I can. you know, optimize this for the goal of account takeover. Is that, that's pretty much where you end up normally, right? Yeah, absolutely. So the final goal is to find an account takeover. So sometimes it would be like you said, post message, sometimes it's even a self-excesses. So if I see a chance to, let's say, find a self-excesses and from there upgrade it to an ATO, I'll do that. Very interesting. So is most of your hunting focused around ATO? Like is that pretty much your primary target all the time or do you ever go for like XSS? Because you mentioned like a self-excesses, is that what you're looking for along the way. Yeah, so with client side bags, the maximum impact you can reach is basically account takeover. So if you find it through an XSS, a self XSS, or a combination of, because when we say self XSS, it's a combination of login, logout, CSRFs, combined with that self XSS, and post messages, so all of that. Joel (05:13.022) Eventually, the biggest impact you reach is account takeover. OK, gotcha. Nice. And I just want to make sure you're keeping the mic a consistent distance from your friend. He's got this nice deep voice, and I want to make sure the mic picks it up. No, that makes sense. And he says essentially, yeah, I just try to go for the max impact possible on the client side. You know, just don't give up until I have everything. That's great. That's awesome, dude. So I guess I wanted to talk about specifically, I wanna go and talk about some bugs right off the bat. There was one blog post you did, and I think this is one of your most recent ones, and you haven't blogged as much over the past year or two, but this is the last one on Meta, and it was a client-side race condition via post message. And this one caught my attention because this is something that I've kind of been researching a little bit, and I was like, oh, you know, and I started standing up some things in a lab and I started playing with it and it seems very possible and then I stumbled upon this blog and I'm just like, frick, Yusef's already done it. So I was wondering, have you had, obviously this was an amazing write up and an amazing bug, have you had similar scenarios like that before where you see essentially state changing actions happening with post message that will allow you to trigger race conditions in the flow that's happening on the other tab? Yeah, so with that one, if we can explain more about it. So it was like. an RPC communication between Facebook and the iframe hosting the game in apps.facebook.com so basically what it does it requests the third party or the game page, requests to the parent the OAuth token for that app and Facebook should reply with that token. What they did at that time they checked the app ID, the client ID. Joel (07:17.388) not any app would request OAuth token of other apps. They did that check correctly but what I found out that if we specify for example another app they'll check the origin in the server side. So for example, if CandyCrash requested OAuth token for Instagram app, it would fail eventually because the origin has to be set to candycrash.trip.com and that would fail in server side. So what I did was initially make the request with Instagram.com origin some kind of client side function that would change the origin check. So because it's an asynchronous request to the server, to the server requests. So because of that, while waiting for the response of that request, I'll just make the client side, that client side post message to change the origin. And now like. because it already made the checks of the origin initially now they completely trust that origin so when it came back it just send it to Dude, I freaking love it, man. So the whole thing is tied to essentially that window instance or whatever, where it's coming from, that reference. And then it just all basically goes from there. Once it establishes that sort of trust with that session or that window, wherever the messages are coming from, then from there it's basically blind. Yeah, so they do a lot of checks initially of the origin on all of that. Joel (09:06.738) and after that they make the request to get the OAuth token and after getting it in the response, they just... Like they don't do checks anymore, they just send it back to whatever origin, to whatever window, the source window, and setting the postMessage to that origin. Ah, so they're using the built-in postMessage, the second parameter in the postMessage, right? A lot of time for the attackers, us, it's star, but for some people when they're trying to control what origin they're sending it to, that second parameter is the origin that they're gonna allow the message to be sent to, is that right? Yeah, yeah. So that second parameter, the target origin, I change it while the request is, the response is being returned. I love that. And so, one I just kind of wanted to brainstorm with you a little bit about that type of bug. Obviously that one's a great one. You have an asynchronous post message they can go through and change essentially the origin that's allowed to receive the post message on the way back while they've already done the checks. So that's great. One of the ones that I was kind of thinking of is when there's a window dot opener check of an origin, right? And what I was thinking was, wouldn't it be interesting if we had three tabs, okay? We've got attacker controlled tab, opened tab, you know, victim tab, right? And when this third tab does a window dot opener check, the original tab redirects this guy. to a cached page on the site that's allowed. So it does wind or whatever. That's valid because it's the same origin. And then real quickly, our first tab redirects the second one back to attacker control domain before this guy does a post message to him to intercept the post message. And one of the things that I did, but like you mentioned in your writeup, the whole rub here, Joel (11:11.842) is there has to be a delay, some action that takes time. And normally that's gonna be an HTTP request, right? Because you'll get a couple hundred milliseconds of time to trigger your exploit. And one of the ways I figured out to optimize this was, the way I figured out to optimize this was, forcing the browser to cache some of these pages. So when the first page does the redirect of the second page, that doesn't start another HTTP request. It loads it straight from the browser cache, so it's an instantaneous switch. So if you send a post message to a tab that's loading, what happens? Does it hang? Like, does it fail? I think it fails. Okay. uh... so what's the question if i if i send a post message like say i redirect the second tab to some other domain and i sent a post message while it's redirecting while it's redirecting yet because there are uh... no uh... so there are no uh... cross origin event listeners for messages. So there are none set yet. So the post message would be sent, but nothing to receive it. So the key here is making sure that you get that timing correctly. And the way that I figured out to do that in my research was getting the browser to cache your HTML page with some specific caching headers, and then you redirect that page that will be receiving the post message right before the post message gets sent, your cached HTML page is already there listening. Yeah, you know what it also makes me wonder is if you could take advantage of certain, like if it's parsing JSON, maybe you give it a really like deep, dense JSON blob that takes it a second to parse so that you could actually use some built-in functionality to force a delay in just processing time. Not even like, you know, caching and stuff, but you know, how long does it take for it to load this giant JSON object? Yeah. Joel (12:59.754) So yeah after the bug I found in Facebook, I actually found a bypass for that and basically the bypass was a part of the bypass was to try to like escalate the time needed to so we can So they applied to a lock mechanism. So when the request is sent there is a lock So we need time to like trick it to not trigger the lock that by I guess sending a lot of post message requests like a ton of them with like each one five megabytes or something like that and that did the trick no way yeah dude that's so cool I did something similar once with a post message bug on PayPal and essentially it was a scenario where I Joel (13:59.348) page right to send the configuration right and I needed to get a post message first and get an ID and then win the race with the with the other post message back to that child post message and the way that I want it was a by not using JSON parse by using string Yeah, exactly, like substring, right? And so I knew that the ID was always at index 23 or whatever, right? So directly. Exactly. So just grab it, substring, go. And whereas the other iframe that was sending it was using JSON parse and doing some other stuff which takes more cycles. So there's lots of fun ways that we can do all sorts of cool stuff like that. So, I mean, obviously this bypass sounds. pretty freaking amazing. I've never thought about sending massive, massive post messages to kind of bog down the side. Have you done any other stuff with post message phrase conditions or just those two? I think it's a pretty rare class. Yeah, so it's actually the post message is just like the communication part. Yeah, I'll let you turn that off. So it's actually like sometimes you'll find. So I view post message, like event listener, message event listener of post message as a source. Yeah. So basically it can happen from the URL. Sometimes you can find the race condition. So let's say on hashChange event, when the hash is changed, it will trigger some stuff like it would grab some text from the current location.ref and try to. Joel (15:44.834) Parasite and all of that. So I guess sometimes there are rejects checks and What you can do is Rescondition the rejects check of the of the hash change again large data Yeah, yeah, it's but it's like It's very time Since yeah, so it's not I tried it worked like maybe once in Thousand yeah, it's a very low percent regex bombing is a thing right like where you can get like, you know Really hard things for red. Yeah. Yeah So you can is that basically what you have to do is like create like a payload that is really hard for the regex To work with so that it takes the amount of time that you needed to take So the rejects basically checks the for example, let's say it checks the URL of a text from a text and if it passes it would do something for example setw to that URL so basically I'll raise condition the check of the the rejects check and the window.location.ref. So because that you understand it, so it would pass the rejects. After passing the rejects, instantly it will change. It's no wonder it was like one in a thousand, right? Because the timing on that, I mean, there probably wasn't even a line between it, right? Yeah, a line, but you can force it. Also you can brute force it because it's a client side. code so you can make it like the page won't reload. It doesn't, in this case, it doesn't need to reload so you can do it like a thousand, hundred thousand times. I think it's really, I think those are really cool types of bugs too because you can use sort of like, I think maybe technically it's a pop under sort of thing for that where you open up a page, right, and now the user's interacting with this page, but then you can do this attack on the window that you just came from, right? Joel (17:57.326) And because you've got a frame reference and you can, you know, brute force, I use that often in these sort of scenarios because, you know, you need some explanation on why the user's just sitting there for, you know, five, 10 seconds while you're brute forcing. Obviously, if it was only a thousand, then it wouldn't take very long on the client side perspective. But, you know, if you're doing brute forcing something a little bit more intense, like I've had to brute force a six digit code before. Via via post message, which is very doable. Yeah, it's instantaneous. Yeah, which was something that I did not expect So that that's definitely an extremely cool bug class. Yeah Well, it's funny because post message is one of those things where it's like you're almost making a request but you're not so like The possibilities with that are so much larger like it's so fast because you don't have to make HTTP requests every single time and so this extra functionality that they like made is, you know user flow ease of use whatever like It's now the hacker's advantage. Did you know like before PostMessage, it was like the two pages were communicating using window.name. Yeah. So sometimes you can still use that for exploits, especially when you need to. get a payload into a heavy CSP environment. I don't know if you've ever done that, but you set the window name, and then you can transfer it away and access it. So that's definitely a nice gadget for transferring data across quickly, but man, is it a pain in the butt, though. And I'm glad we have post message now instead of window name. So you mentioned, I wanna go back to something you mentioned before, you said, and I don't know why I never really thought of it this way, but you mentioned the on hash change event. Like of course, I don't know why that hasn't been in my client side perspective of looking for wind hash change, you know? And so that's another great source, and I'm wondering actually, and I don't know off the top of my head, can window.opener change the hash of the other page without... Joel (20:01.418) redirecting the page without like refreshing. Yeah, without refreshing. I have stories later. Oh, let's do let's do it, man. Yeah, I want to hear it right now. So basically, do you know, like when you go to Google and search for a couple of words? Oh, my gosh, I love I love how this story is starting. OK, so when you search for and pops up like an article, when you click on the article, it will automatically particular paragraph. Yes. So this is like a technology known as scroll to text fragments. It's supported by Chrome. So basically- Is it a Chrome only feature? I guess it's Chrome. Like the last time I checked it's only Chrome. Okay. So basically you specify in the hash part, like you put colon slash colon takes equals and you put like suffix and prefix and suffix. And basically Chrome will look in that page for that paragraph or that stuff and scroll directly to that one. So what's how I have used this and actually this is was zero day in Chrome back then when I used it. It's reported on page. Yeah, yeah, yeah. Dude, this is great. I love this. Yeah, and we wanna talk about this too because you found some other browser bugs, but yeah, continue, yes. Yeah, so basically what I did was trying to Let's say look in the page for certain words for let's say like you can't look for CSRF talking. You won't find it as text. Yeah. But we'll talk about this. So what I did first, you have to detect the scroll. So is this a cross site leak? Is that what this is? Yeah, it's a cross-site leak of page quoting. Dude, this is so smart. Why did I not think to look at this? Yeah. Yeah, but here comes the part of the redirecting window to the opener and changing the hash. So this check of every time the hash changes. Joel (22:12.862) in the page and scroll if you find the text it would only happen if the hash was changed from same origin domain. So you can do it for example from attacker.com wind equals and only change the hash right it won't work because if it's cross origin domain it would require each it would require user gesture every time. Would it work if there was a cross origin policy set in the headers on the domain? Look, could you update it? Like is it blocking you purely because of browser security or is it specific to this? specific to this feature it won't do the scrolling the searching of the text and then scroll unless the hash was changed by same origin domain so the first part of the attack is to find a page let's say in Facebook.com that would we can control to set window dot opener to a certain URL so for example we can set make this page return window.opener equals https facebook.com slash certain endpoint. Sure. It won't allow for example JavaScript's URI scheme but still allows facebook.com slash. And of course you just had that in your pocket. You know. Yeah I had that. So yeah. I had that and. Of course. This is why, let me just. This is why we really highly encourage. going deep on programs, right? Like this sort of a masterpiece of a situation where Youssef comes up with. Joel (24:04.99) like a browser quirk, and then you need the specific piece of functionality. If you know an application, especially one as big as Facebook, inside, outside, upside down, then you'll have a list of these, and I'm sure you keep a list of gadgets as well, of things that you've found that are like, oh, this could probably be helpful someday, but I don't have a use for it right now. This is something that I think not enough people do, and if they would, then they'd see a lot bigger success in the Bug Bounty Realm. Yeah, so sometimes you see something interesting in the... client set code or even an endpoint that returns something and you just ignore it you feel like it's interesting but you ignore it but I advise anyone to just save it in a note for example one time in during a live hacking event with Facebook I didn't find any bags I just went through the notes and I found the you know that post message XSS DomXSS the one that like I have a page You're gonna have to be more specific, Yusef. You have a lot of postmessage.excess. So let's not go... Yeah, yeah. I forgot that one, but I just found it from the notes. I just went through and I got second place. Yeah, that's crazy, man. Yeah, I do. I do remember that now. Yeah, I think it's like... Yeah, you remember that one time I got DomExcess? I was like... Yeah, yeah, I can think of a couple. But yeah, OK, so back to yeah. So basically with this one, as I said, you need to have the redirect or the change of the hash from the same origin domain. If you have that, you can basically search in the page. It would scroll to a certain part of the page if it finds that word. The second, and this is the zero day, it was... I was like, how do you leak that though? Yeah, so it was like, if I iframe that page, and when I iframe that page, you know sometimes when the iframe scroll, the main window would scroll too? Yeah. Yeah, it happens. So I was able to detect the scroll in the iframe with the scroll in the parent window. Joel (26:29.65) So with that I can have a confirmation if a word is found in the iframe or not. Dude, that's crazy. So, okay. Joel (26:47.338) Wow. Would you scroll on the parent page or on the iframe? So the iframe, the scroll would happen if the word was found using the scroll to text fragment. If the word was found in the text, it would scroll in the iframe. But unexpectedly Chrome also scrolled the parent window, so both of them scrolled. And would it do both on load? Because you can put it in the URL, right? And it would just... fragment okay it was scroll to that text in the i-frame yeah okay but that scroll triggered the scroll in the parent as soon as it loads yeah so also because you can way yeah that's one allowed me to like basically load any page in an i-frame and search that page and detect if the word was found or not Wow, and the only requirement being that you need a gadget where you can set the... Make like a client-side redirect from that domain. Gotcha. So for example, a page that would do window.opener. location.ref equals that domain with the hash. And that would, it's so. That's actually not a very uncommon situation with post-message related stuff, I think, too. Being able to do hash-based redirections or injections into window location.hash. But it can be window location.hash, not. window.location.href or does it have to be href? Yeah, it can be hash. Oh wow. But it's rare to find.hash. Yeah, yeah, yeah. And also it can be like the same page with the set window.location.ref. It's not like opener setting opener. Yeah, well, I say it is, I guess, it's rare to see wind but it's less rare to see pages where you can do. Joel (28:48.182) where you can control the routing in these sort of client side page routing situations, right? You know, where you've got this whole route table that's set up for the hash fragment, right? If you have a gadget where you can control that. then, wow, but I guess it depends on whether the, yeah, because you would need the, well, if you're not trying to leak something that changes, then you can do it over multiple refreshes. Yeah, yeah, so, so. Dude, that's nuts, man. Sometimes you can do it with the refreshes, but sometimes because, for example, this is the, like, there are more, there is more to the story. So yeah. Okay. Thank you. Sometimes if you can, let's say, turn the row page so you can change content type set to text plain so now it won't be rendered as HTML so now you have access to datter you can you have access to the CSRF token you can query it I was gonna ask yeah so the whole thing is now text so now you can search text anywhere within the whole thing but you still need the gadget don't you yeah but the gadget not in that If you found like the gadget that would, let's say Facebook.com has an endpoint, that endpoint returned to JavaScript that would do wind equals and you control that part. So now you can change that page, opener page, to this, like the one that... Ah! Dude, what the heck? This is crazy. So then you've got that middle page, and then you're using... So every time I want to... No, I'm thinking about it wrong. Every time I want to change the hash in that page to look for a word, I just... You're using the upper bold to update it. Yeah, so I just reload the endpoint that has wind I just reload it, change the value of the... Joel (30:57.094) the value set and it would make the change in the other page. Because the event has to be triggered by a change, right? So you have to change the hash or you have to change the URL? It has to be changed by same origin domain. So it requires some other vuln. You can't just load the URL once because that doesn't change. Like the hash isn't changing. But if you load a URL that then changes the hash, that triggers an on hash change event, which then you can pick up and it scrolls and then you can... So that happens, it's not like JavaScript code, but the browser detects on the hash. I'm seeing it now, man. Dude, this must have been the most badass POC video for this, you know, like just see the thing just go shwoosh shwoosh. Yeah, but there's more. Oh, there's more? I mean, I was going to ask about tree. This is like a freaking, you know, like, you know, blowout sale. But wait, there's more. No, this is great. So the SCTF, the scroll to text fragment. so it doesn't detect character by character so it's worse like for example you can't like reinforce the CSRF token because it's yeah it's like 16 bits or whatever you can't you can't actually look for that you need character by character in YouTube in Chrome the separation of words is using spaces, using whatever, I guess spaces and... Peresia, maybe, or tabs. So what I did, if I can find a way to change the page encoding, for example, if it's not specifically set to UTF-8 in contained type, if I can control some part of that page, I can inject a few characters, and the browser will assume that it's not UTF-8, it's UTF-16. Joel (33:00.676) Chinese words as no yeah Chinese words like they have like yeah it's separate and then you can D you can decode that back down to you to if you what the heck this is some Matthias Carlson shit okay now I need to ask when you submit something like this to a triage like what Do they understand it? Like how much back and forth do you have to go through? Yeah, so actually this one didn't, it wasn't reported. Some parts were reported to Facebook.com, but this back with the Unico change and everything was reported to. Program that I can disclose and they had like sometimes hard timing to understand it, but yeah, eventually they did and they fixed it Wow, dude That that's great. And I guess your reports need to be very in-depth in order for them to be able to Reproduce all that so that's amazing dude. What what a what a great example of the persistence needed to do this job because I'm sure you didn't like just see all of that. I don't know, maybe did, but if I were you, I wouldn't, going into that situation, I wouldn't have seen that path straight from the beginning. It would have taken me a lot of iteration on top of, well now the spacing is wrong, how do I fix that problem? How do I get this to be a same origin redirect? What's going on here? So there's a lot of persistence that's needed there to try to figure out all those things. Joel (34:35.058) So sometimes like an advice if a new feature comes out, you just go to the standard page, read it, and also the discussion page in, I'm not sure in GitHub or in Chrome. In Chrome, yeah, you'll find like documents, they share documents how they like want to protect against this security threat, how they protect against this. Sometimes they'll have like... Accepted risk and that accepted risk you can use it to Launch another attack in some scenarios. Yeah, interesting Do they ever push back on that because it is accepted risk because they go well, this is accepted risk So we're not gonna take that. Yeah, but push back against a use of report. What are you crazy? Like no try to die no, but the browser guys thought that is accepted or Like for example, they didn't require user gesture with client side redirects originating from same origin domains. I guess now they do. So after this with the brute forcing and everything they do now. So sometimes they're not convinced about something and after that they change, yeah. Wow dude, that's an awesome story. So glad we got that one right in the beginning of this episode. That's awesome. Um Wow, uh, i'm not i'm not gonna lie i'm a little bit stunned on that so Yeah, so I wanted to ask like it sounds like a lot of your bugs are very Multifaceted like there's a lot of different aspects. There's a lot of different moving pieces and stuff You mentioned you take notes how like is it super detailed notes? And how much are you going back to those notes? Because I imagine as you're hacking you're like Some of it's clicking. You're like, oh, I have this thing that will work. Yeah. But some of it, maybe not. And is it, is it all just notes or how are you keeping track of that? So I just keep a screenshot of a verb like, or sometimes I just have a, like, a note that this page returned, let's say, a client side code that would change window.opener. Okay. Uh, the other one would make a post message that I can control. Joel (36:54.318) Uh, like control the content. So that the notes would be like this, like, uh, this one allows me to do this. This one allows me to do this and that's it. It's not like deep, deep. Okay. That's cool. That's awesome. I mean, I feel like everybody I talk to, like notes are like a huge part because there are so many like potential things that we come across that are useful later. And I think the bugs that you submit, especially like, I can't think of anybody. who does like that level of chaining and like vulnerability, like combination that you do. I feel like every bug that I see, it's always like, there's multiple pieces and it's so creative. Do you ever dupe? Like do people ever dupe? No, never? No, like the last time I duped, yeah, it was in 2018, I guess. Or 2019, yeah. This guy hasn't duped in six years. That's crazy. Wow, dude. That's amazing. So. Thank you for that story, that's great. And I kinda wanna come back to your post-message flow a little bit here, okay? So what kind of methodology do you normally use for this? Because we've got a couple things. I'll sort of state the obvious, we'll get those out of the way so that we can go into the more interesting stuff. You know, you've got, when you've got multiple pages, multiple frames, tabs or iframes and stuff like that, that's always a place that you're gonna wanna look for that sort of post-message-based communication. And you've got, you know, obviously you can see if you've got the post message tracker plug-in installed You can see the post messages flying between the page and the global listeners on the side So like what is your go-to methodology for identifying those things? You just read the JavaScript like read the JavaScript straight straight. Are you looking specifically for the listeners? Yeah, so the first thing I do is Thanks to friends with extension. So I just grabbed I see the the part of code that said the listener, I just go to the source code and get like that part and start looking if it looks interesting like they're accepting some data, they're using that data to do something, I'll just continue with the resource, otherwise I'll ignore it and move to the next one. So that's it, like one by one. Joel (39:15.358) Sometimes if I see something, I see for example, a listener from Google, let's say from GS, like the one, SDK, GS SDK that you include to do like Google authentication. So I just ignore it because I'm sure, I tested before it's safe, so I just ignore it. I ignore for example, ones talking to iframes that are third party, they are sandboxed unless they're leaking some interesting stuff to that third party iframe. Yeah, and in those scenarios too, I've also seen sort of an inverse thing, like if you can pop the thing in the iframe, then you might have the ability to leverage something back on the parent frame, you know, because that listener is expecting something specifically from that. Embedded host right and then you have the ability to talk to that parent frame Yeah, so if you read the code and see that for example it only accepts post messages from origin, let's say Sure plug-in dot-com and that origin is from that iframe Okay, and it has some potential. I just go to plug-in dot-com and try to find an access there to inject the iframe and from the iframe, just send or directly send. And especially on hyping targets like the ones you're used to working on, you know, it's worth that extra effort. If you can guarantee, you know, if you can open up your browser tab and do a post message, you know, back, or your browser console, I mean, and do a post message backup and verify that there's a bug there if you can get an XSS on that, you know, child domain, then it's very much worth the time to go get the XSS on that child domain. and then pop that big bug by going back up the stack, right? Yeah, I do that. Like maybe if it's very deep, let's say, iFrame and from the iFrame, I have a story about this with Facebook, actually, and it was very interesting. And it was like maybe a chain of four bags or five bags. Yeah, so... I'm very interested. Yeah, it happens. You've got my attention, Youssef. Joel (41:38.41) Yeah, so just one more thing with the post message. Sometimes you find that there is an iframe to plug in or let's say a logger or mark. You know these iframes for marketing, logging. Oh yeah, all the time. For the clicks and some. Sometimes it's not doing something critical. But the parent page is sending critical information like window.location.ref is sending it to that iframe. So now I'm interested in the iframe. If I can find an XSS in that domain. Hijacked iframe. Yeah, hijacked iframe receive the window.location.ref. And OK, it doesn't have a lot of data, but I can, for example, do. or redirect to that page and leak it from there. Is that something that you often, so I actually had this in my list on the account takeover section because I wanna pick your brain about account takeover stuff too. Is that sending off alarms in your brain when you see, okay, I can control the page to which an OAuth code is being sent to? Is that often a big thing for you? Yeah, so for example, that one actually triggers. OK, it depends. If I can only leak OAuth code to any endpoint, OK, it's interesting now because it's not that interesting actually because I need to find an endpoint that would pass its current parameters to to redirect or something like that. So I need to find, it's easier with hash because if it's in hash, I can just find an open redirect and the browser will carry the hash to. A 302, right? Or like, you need a server-side redirect for that, right? Yeah, yeah, yeah. But with, if it's code, it needs some work, but I accept it, like sometimes I just do it. Joel (43:40.37) Also, there are many things that trigger my head. Yeah, yeah. Yeah, I wanted to ask, well, maybe I'll save this until after, but I was going to ask, when you look for a count to go over, is it always low-level type of post message, like technical bones? Or are you looking for like, I changed my email on the profile page and something goes wrong here. Like, do you ever look at it from sort of a user perspective or is it always like HTTP, browser, JavaScript? That's what I'm saying. So you're talking about account takeover that can be caused by server-side mischecks or misconfigurations? Yeah, I do that a lot. But not with companies I usually work with, like Meta, because they have that, yeah, you can't hear. They've kind of got that squared away. But let's say I have few examples that are great, actually. So for example, let's say certain company uses Facebook, uses Apple, uses Google. Grave mistake. Yeah, yeah, yeah. Never use Facebook in front of Youssef. Yeah, yeah. So in that case, you'll have to, for example, they'll check after the whole flow, they'll check the email. Right. They'll not check. the user ID or something else. So when they read the email from Facebook, from Apple, they completely trust Apple and Facebook and they just log you in to any account with that email. So now if I can find an email confirmation bypass in Facebook, an email confirmation bypass in Apple, I can hijack that company, any account in that company. Yeah, or one of the ones we've seen is like, if you're passing an access token directly, then sometimes they will just check the email associated with that, not the app associated with that. Have you seen that one? Yeah, I found it actually. That one, because they didn't use the official SDK by Facebook for a certain program language. Well, I was going to say, another one that we've seen is like, you'll create an account, then link your Facebook account to it, and you can change your email. Joel (46:01.954) on the on the vulnerable site and then you just log in with the same Facebook account and it's tied to the maybe that's what You were just saying but it's tied to the account ID And so there's like two separate account references that are get linked together here And it's a really matter what is on your Facebook account as long as it's valid Yeah, so I guess we've got that you mentioned a volume story and then we got we got on a little on a little Little tangent there. Do you want to go back to that one? Okay, so this one is a combination of a lot of stuff, post message and also cryptographic secure functions and not secure functions in client side. Yeah. Like thereof, yeah. Yeah, so basically Facebook has this messenger chat plugin. it's included in the JavaScript SDK in the clients in with Facebook so basically when you when you use the plugin it would just pop up a chat and you can chat with that page in Facebook so actually Facebook use that plugin in their own website in an endpoint like facebook.com goals marketing something like that so it loads the plugin and that plugin at some point it has a dom xss but to reach that to reach the point to exploit the dom xss that's the hard part that we'll work to we'll try to do So the communication between the iframe, the iframe holding the plugin, this chat plugin and the main page facebook.com slash goals, they are communicating and they're doing like some kind of check. The check is a callback for example if you have a post message from the iframe to the parent Joel (48:16.542) it should have like an ID, a certain ID, which is let's say random stuff. And if it's true, it would allow it to call many functions and where the new XSS happens. We see this quite, this is a pretty common thing with post messages where there's like a, you know, some sort of random ID or some sort of, and then that is tied to a specific handler or set of handlers. That, you often see that. Yeah, I've seen this on mobile as well, actually, with like JavaScript bridges going between the web view and the same exact thing. Yeah, so tell us how you broke it. Yeah, so basically this, I went to the part how this ID is generated and it was generated with math.random function. This function is not cryptographically secure, like what that means. the pseudo random generator If you can leak four or five values of math.random you can reverse to find the seed and from that seed you can predict the next value of that random number so what my objective was to leak the like three or five math.random values of that page and from there I can predict the next one or I can reverse and find the callback ID for the two used for communication and to leak that math.random IDs, they actually named the iFrame, you know, window.name So they use the same function they used to generate the callback IDs. They use it to generate the window.name. Interesting. So now if I'm able to leak window.name of an iframe, if I can leak it four or five times. Joel (50:20.638) without refreshing the page because that would set the seed. That's what I was going to say. I literally have done the same bug and actually shout out to Donut, my man Donut, because he's done a talk on this and I pinged him. I was like, hey, I've read your talk. I still don't understand any of it, you know, on the insecure, you know, pseudo random stuff. And then he kind of walked me through it and we figured out in my specific scenario. It wasn't explodable. But it sounds like you found a way to actually leak some of the seeds without refreshing it, which is a. This is once again, is this gadget after gadget after gadget chained together to create this. So yeah, continue. So the Facebook.com page in mobile, like this is related to mobile. Okay, all right. So in mobile, they returned like, they returned X-Frame options with allow from. So allow from is located basically and it's ignored in mobile and even in desktop version. So basically that page can be I-Framed. Okay, I'm sorry, so. Facebook.com. X-Frame options and then there's allow from and then it specifies a domain. And that's depreciated so it just ignores it. Yeah. Interesting, that's for any of you recon people out there. That'd be a good thing to hit like mass search for to see where there could be this configuration where they're thinking they've got a secure X-ray configuration, but they don't. Very interesting. I'm sorry. Continue. Yeah. So that page, facebook.com slash goals. that page that load the iframe with the plugin now is iframeable so i can iframe it in my website in mobile so when i iframe it uh... so attacker.com can access the inner iframe of course and can read the name of the iframe Joel (52:11.142) so I can leak like one value of math.random because I can read the iframe name which is like users was generated based on math.random. Wow. So after that I'll just send another so the way to not refresh the page to maintain the same browsing session. Yeah. So they had like other functions or that you can access without having that certain callback ID or certain that ID. One allowed you to refresh the iframe or to try to create the plugin or refresh the plugin. So each time it refreshes the plugin, it's generated a new window.name and generated. This is absolutely ridiculous. This is what it works out like that. This is nuts. Yeah, I can't even. So now if you leak five, even if they're separated, for example, you have a math.random value, then one that you couldn't leak, then one that you could leak. So even if they separated by one or two, you can actually find the seed. So I found the seed, I calculated the next math.random and got the ID, used the ID to It's so cool because this is like almost a CTF challenge I feel like I haven't even thought about like math dot random in sense like I did CTFs, you know, like And it's so interesting. I didn't realize that JavaScript math dot random was vulnerable to that as well Yeah, it's been four years. Wow If only somebody could fix it They have like now secure crypto. Yeah, they have it but it's math random is still vulnerable Joel (54:11.946) It's still vulnerable but it's faster So uh... There's like a secure random class, right? Is that what you mean? Like the two separate? Yeah, so Math.random is variable to these type of attacks, but they have like a safe one in JavaScript, crypto, yeah, I think it's crypto API or something. And it's totally safe. Wow. Well, a lot of people still using Math.random. So definitely, definitely interesting thing there. And then that whole concept of... you know, graphing all these random, you know, these points that are in the random generator function and then generating the seeds off of it. Really cool. I loved that research by Donut and others as well. So very cool there. So I wanted to kind of, so that was a cool, a mobile piece as well, which is great. I wanted to see that. And I kind of want to go back to what you mentioned earlier. You said a lot of things make the alarms go off, you know, in the head. And that was one of the questions I had here. And so here are some things that I could kind of come up with off the top of my head. Um, you know, OAuth flows, any sort of domain handoff of information, post messages, cookie bridges, et cetera. Those are all things that kind of make my, my brain kind of go, Whoa, wait a second. Uh, I think I should be paying more attention to, uh, hash changes. from this conversation that we've had, I'll be paying more attention to that in the future. Can you think of any other things off the, I know I'm putting you on the spot, but can you think of any other things off the top of your head that sort of get the alarms sounding in your brain? Yeah, so sometimes not a lot of people would look in, Joel (55:56.098) DOM generated HTML, for example, if you have like GS code that would create an iframe and iframe sources set from unknown... source. So we have a sync. Like many syncs, they're not known to people. Like, for example, if you set the action of a form to JavaScript, you risk him it's an excess. If you set the iframe source to JavaScript, you risk him it's an excess. So sometimes I just focus on things that Let's say, uh... Like using Create Element, docu and then you kind of see where... Yeah, yeah, it's not like direct inner HTML set or something like that. Interesting, interesting, yeah. Inner HTML is one of the things I always search for, obviously, but I don't always search for create element. That's smart. And then specifically for these specific types, we've got, you've got source, or I'm sorry, you've got script, you've got iframe, you've got... What are some of the other ones? Form, yeah, form. And then setting action. That's good. Would you say you start more at sources or syncs? Joel (57:14.634) Yeah, I wanted to ask this too. So most of the time I start with sources. Yeah, but man. Give me some right here. Team sources, let's go. But in the VSC, I'm all about the dopamine hunting. I need a sync. Get out of here, Joel. Get out of here. Because even if you find the verbal sync, you have to trace it back and you do. But with sources like. It's obvious where the app is going. And I think source-related stuff also lends itself to gadget hunting. You know, like even if you don't have sync, even if it doesn't result in an actionable vulnerability, you can do stuff, you know? And that's what I'm all about. I think I get a, hold on just a second, sir. So you mean the 50 unexploitable bugs that I've been documenting are useless? Shut up, Joel, hold on, no. You know, the just, I'm all about knowing what I can do with the application as an attacker, right? I wanna know every place, every location where I can affect the app, you know? And I think hunting from sources really helps you understand holistically what an attacker is capable of doing in the app, even if it's something benign, you know, like creating an element on the page that you have no control over, right? But it inflates page size or, you know, who knows? Maybe some random cookie gets sent and you can, you know, and it's a randomly generated cookie key. and then you can inflate the cookie size and cause client-side DOS or something like that, and then use that in a different bug. So with sources, you always end up with something. Yeah, exactly. Something that's worth it. I'm gonna clip that. I'm getting indirectly roasted out here. This is... Ha ha, scoot forward a little bit. Ha ha ha. No, that's great, man. I'm glad to hear you say that as well. Sources are... Sometimes, but sometimes, like, I look for things that... Joel (59:10.91) Yeah, I look for things before sources. All right. In certain conditions. Let's ignore that part. Anyway, Yousef, I've got some other questions for you. Go ahead. You do look for things? Yeah, yeah. So like I said, if I know that page is setting the iframe, it's creating an element iframe or form or something. And I'm sure they're using a source that I control or something. look for things because I'm sure that eventually they'll use my source or Yeah, because I guaranteed the source parts or now I'm look because you know what type of stuff you're looking for Yeah, for example with like the iframe so if you're looking for changing the href You're looking for changing the URL or the window location through JavaScript Like so you're gonna target a sink instead of looking for an entrance got it I'm looking at my notes here and we sort of covered a little bit of this already, but I'll repose the question which is, you know, so similar to an OAuth code being sent to any path on the thing, like if you can control the path with the redirect URL, right? What are some other things that you've seen, since you specialize in account takeover, what are some other things that you've seen that result in account takeover? And what I've learned from you already today is leaking location.htref is pivotal. And so I assume that's one of them. Yeah, yeah. So also self-XSS. Basically having self-XSS, you can leak the OAuth token. Most scenarios you can do it. So for me, in some targets, self-XSS is directly an ATO. Does it have to have a CSRF to update, like to trigger the self-XSS? Because I assume your taxing error basically like, attacker loads page, updates an XSS to themselves, which then triggers your attack or? You're talking about triggering the self XSS via CSRF login and then- Yeah, you have to have a CSRF. Yeah, so basically that's why it's called self XSS. So you self XSS yourself in a certain session in the victim browser to actually trigger that XSS in the- Joel (01:01:31.05) that frozen context from that origin, and all of that to actually, for example, access an open-ended page from the previous session to read the window.location. I've used that before, right, where you have a page that's already open, and then you establish a self-excess, and then you go back up and reach over and grab it and bring it back in. That's interesting. It would be more interesting if we could figure out how to actively have control of the victim session in a different tab. thinking about this the other day, and I was wondering whether it's possible to manipulate same site cookie policies to create two separate sessions inside the browser. And so, like say for example, I've got my attacker control page that's got an iframe, that iframe is not a top level navigation, so it's not gonna have cookies sent to it. And then within that iframe, I log in myself, trigger the XSS, reach back through the parent, and over to the opener tab, site the victim site and that site still has the session open of the victim but it's an isolated cookie session have you seen anything like this before do you think that would work or is there am I missing something here I'm not sure yeah because if you said the cookie is set I'm not sure it would be set in that context well we'll look it up I tried to look this up the other day and I actually did an experiment on my own little website with various origins and I don't think that cookie is set on that other tab which makes me think that those cookies are still, there's like some sort of different context. I said, and I'm sure what's going to happen. Yeah, it's probably like some sort of cookie store. Cause like on Chrome, for example, if you open the application tab, you have like cookies that are associated with that application quote unquote. Um, and it could be that it's basically just not reloaded from the, like it has to load it from the browser, from the cookie store in order to have it associated with it. Yeah, that's what I'm thinking. I think that could be a really, and I'm sure what's going to happen is after this episode airs, someone's going to be like, hey Justin, here's the solution to this, which I love. So please, continue to do that, people. This is one of the things I love the most about podcasting is I get free research from people that just send me the answers to the things I wanna know. But it's very interesting, and I wish I had the answer off the top of my head, I got pulled away that day. But I think that would be really interesting, right? Because then you would actually just be able to control that session with the other cookies. And that would be a new way to kind of execute self-excess. But. Joel (01:03:58.454) who knows if it'll actually work. Sometimes you don't actually need all of that. So for example, you established a certain state in that page. Just leave it like that and start to do all the logouts, CSRFs, logins, CSRF, and everything. And just come back after all of that and exploit that page. Because it won't reload unless they have like a client side code that would, for example, if it detects cookie changes, if it detects a logout state, it would refresh. Unless they do that, you're safe, so just keep it waiting and do the self-excesses and come back. Yeah, that's one of the biggest arguments, I think, for putting CSRF protection around login and logout mechanisms, is that any self-excesses can be really... badly exploited in a situation like that if you have both of those gadgets in place for login and logout. And this is another con of using centralized log in system. Because if you've got the cookies isolated to a specific domain and then I hit login.whatever.com and that still has its session live and I can re-log in. If they don't fully log out the person out, then that can also result in some bad stuff. and as well as social media logins and that sort of thing. Also some things like for example you have a self-excesses let's say in Facebook.com but because Facebook meta have like this centralized like let's say a platform For example, they allow some things to happen from workplace.com, access in Facebook.com, Facebook.com. So if you find the self-access in Facebook.com, you'll just target directly workplace user, you'll just target an Instagram user, because they have like- Because there's these bridges. Bridges, some kind of bridges. That's a great point. And one of the things I've mentioned to my mentees recently is like, anytime you see any sort Joel (01:06:12.548) Domain bridging. Yeah, you've got to fully deep dive that and we see that, you know Let's just say I have plenty of live hacking events that we've been involved in There's been issues with that and so it's definitely a great spot to continue to look for vulnerabilities All right, so let's move a little bit here to well I've got a couple directions we could go here. We could go and talk about window frame relationships, window.opener, window, window.parent, that sort of thing, and sort of different ways to establish references to windows, or we could go the message port route. I don't know, let me just ask this. Have you done anything with message ports inside of post message related? Yeah, I once found an ATO with the message port and. message channel. Okay, nice. Yeah, so basically message port is like port you can use to communicate instead of, eventually it uses post message, but initially you create a new message channel. Message channel has two ports. You send with post message to the... the target page you want to talk with, and you include the message port, one of the message ports from that message channel. Okay, interesting. So you, and I found a message port bug before, but it was very rudimentary, so I didn't actually have to fully understand the message port functionality. So are you able to send the message port reference? Yeah. Cross origin? Yeah, cross origin you send it in post message. And it can only read once message port it can only be read once by so you can't like for example save the reference or so it can be consumed one once okay interesting okay so basically what they why they do that so they establish let's say attacker Facebook calm want wants to communicate with a certain domain and they don't want to Joel (01:08:33.388) check everything to the source check they do it once and they do all the checks and if all the checks are good they share with them the message port now that new message channel is totally safe we can trust each other we don't need to do origin checks yeah lovely okay is there any catches to that you know yeah so basically if you can leak that message port that have the communication without security checks. If you can leak it, basically you can do a lot of stuff. Is the message port reference just like a string or how do you like pass it? Yeah, so it can be passed in ports, in ports in post message. So post message allows you to share message ports or object message ports. Interesting. So I feel like there must be some way to like fetch it by name. and the underlying APIs, right? Like somehow the browser is able to fetch a message port object off of that name so that it can communicate with it, right? so yeah no actually it use it that reference of message port to just make a new object and then it just no to use that to send a message yes so in memory as they have like uh... because uh... to of them that they are they have uh... different uh... origin so they have like some kind of uh... maybe uh... like memory, in memory they both can access the same buffer, I guess. But, this is, so when you said that, like what is this, I'm looking at the post message NDN right now, and it says, or MDN, it says. Joel (01:10:19.598) there's an option for PostMessage to take three parameters, message, target origin, and then transfer. Transfer, yeah. Transferable objects, and I've never even, I've never. So, cloneable objects. So, for example, the rejects can be shared. We're gonna make a new, we're gonna have a new session now where we quiz Youssef on MDN documentation and see if he can recite it word for word. Yeah, yeah, yeah. Continue, continue. A lot of objects can be shared but not like... So let's see, there's array buffer, message port, readable stream, writable stream, transfer stream, web transport receive stream, that's interesting, web transfer send stream, audio data, image bitmap, video frame, offscreen, and RTC data channel. Very interesting. And so when these are transferred... I wonder how it actually is that a part of that E object that you that you get when you do so they maintain the same object prototype they that's why it's not actually interesting really because you can't like change for example the object you can add, for example, something. It shares the data, of course, but it doesn't change the prototype. Ah, okay. So, because sometimes, like you... I found a situation where there is a check if it's a string, and after that, they'll do something treated as an object. Okay, so maybe if we can manipulate the... manipulate the prototype. So it's a string but it contains let's say a key called safe equals something. So you can do that with the transfer, the post message transfer. So it maintains the same prototype of that object. There's a lot of really interesting information in this doc. There is actually a nice trick there. So C target origin. Joel (01:12:28.362) A lot of people assume that it needs to be string, but actually it can be an object with a key target origin and a value equals to the actual origin. This, you can use it to bypass a lot of checks, string checks. Yeah, if at the time the event is scheduled to dispatch the scheme, hostname, or port of the Windows document does not match the provided target origin, it will not be dispatched. Only if all three match will it be dispatched. Dude, is that? Yeah, and the... This is really interesting. Huh, I did not know that. So you can provide it with an object there that will, because then it, so look, I'm sorry. You've probably got it in your head. For those of you that are listening, not watching, I'm sorry, we're looking at the end. But look, see, the post message has two, has two sort of... What's the technical term for that? It's like overloading function of... Overloads, yeah. Yeah. Function overloading. And one of them is message options and one of them is message target origin. The one that we normally see is message target origin, which is the string. But there's also the one with options where you can specify target origin and also specify transfer objects as well inside of that options. Very interesting. So if you have the ability to affect the second parameter directly of a post message request. then you can specify a target origin key inside of that object. Yeah, so sometimes they'll check the target origin as a string. And for example, if it's an object, they'll ignore it or not sure. So you can bypass the first check and set target origin to the domain you want. Oh, crazy. I'm clapping into the mic. And again, this transferables object thing, we'll put a link in the description. But. the behavior of this. Like I was just reading through how it explains how this works. And it's very similar to what you said, where it's like, when you transfer an object, it literally moves the memory, the block of memory to a different ownership. And depending on the type of object, like it says here, for example, when an array buffer is transferred, the memory resource that it points to is literally moved instead of copying the data. Other objects are transferred by copying the associated resources and then deleting the old one. Joel (01:14:48.102) so they actually had like you know now they have site isolation but they had like the possibility to share to have a shared buffer shared using post message and the two sites will for example if you make change to that buffer it would be changed in the other one so that time so this I actually used but they didn't succeed so let's you share shared buffer and you keep it as it is for example with origin checks with everything when you reach the point where for example it would make a post message to me with that origin I just change the shared buffer and it would be changed in that yeah basically race conditioning That's so interesting. I need to look at the transfer. Dude, I'm telling you man, post message is the shit. I love post message. That's great. And so the other thing that we had from before was talking about window relationship, window frame relationships, okay? So I'm just gonna kinda talk through a couple of those. We've got the window.opener, right? That's the tab that's opened the current page. The window.parent, that's gonna be your. your iframes parent. And then you've got some other things as well. You can traverse into different frames by using a specific window reference and then.frames. And that will include all the frames associated with that page. And then, but I'm a little bit confused because I thought I did something recently and it didn't work where I had a child page that did a window.open. Is that populated into the window frames or does it need to have a specific reference? Do you know? off the top of your head on how you can get a reference to, let's say I open up a page, right? Okay, you need to keep the reference in the variable. You can't access it directly like that. Yeah, so if I control the page, yes, but if it's a different origin, so I pop open a page, that page pops open another page. There's no way I can get a reference to that third page. It's impossible. It's impossible, ah, dude, that's so frustrating. I know. Joel (01:17:05.826) that there is something that I read. By name. Yeah, okay, so. Have you ever done anything with that? I couldn't get it to work properly and we talked about it on the podcast one time, but I don't remember whether we actually got it to work ever. This will work if the pop-up window was opened from a different frame on the same domain. Same domain, yeah. On model. Windows, yes, it also says on my... You're talking without speaking in the mic. I'm just, I'm in my own zone. In modern browsers, this will even work if the window has been opened from a different frame on a different domain, but this can cause some strange behavior in Internet Explorer specifically. Yeah, so maybe that's worth looking into. Yeah, yeah. But that is super interesting. So by window name, you can basically... Not window name, like when you set window.open, you set the name of the open window. Later when, let's say... Joel (01:17:59.074) Yeah, it's actually... If you call it again, it just uses the same... Yeah, yeah. I wonder if I can store frame reference. So for example, I have attacker page. Attacker page opens up another attacker page frame, right? That page opens up another frame with window.open specifying the name parameter. Then this guy gets a reference to that one because this is all same origin at this point. Yeah, you can have... And then this guy redirects away. I still have a reference to that. I'm sorry, this is terrible for any of you listening on the actual podcast, because I've got my hand and I'm just waving it in the air. So let me try one more time, I'm sorry, Youssef. So I've got an attacker controlled page, that opens another page. And then, so this is page number two. Page number two opens up a new tab, and these are all same origin at this point, with window.name, or window.open, specifying the name parameter. And then the second page transfers away. but you're still able to reference that third page from the first page. Yeah, I don't think it's possible. You don't think so? Yeah, I don't think so, because the middle page is lost, so unless you keep the reference to a variable. Right, that's kind of what I was thinking. If we can reference, if we can get a reference to it, and then we read it out. Yeah, because you can actually access. Yeah, because why can't you open a new tab, store that as a reference in memory, with a named tab that you know is gonna be reused? And then say your website you're attacking, the victim site, does a window.open with the same window name. You still have a reference to that because you controlled it originally. And it's going to update that existing window to the new URL, right? So... I have no idea, man. This is definitely something I'd like to see more research on, the window name. Yeah, sometimes the iframe can be the opener of the parent window. Yeah, there are some tricks that you can do. Yeah. Whoa, hold on. Pull up. Say that one more time. The what? The iframe now is the opener of the parent window. So when you look in opener in parent, you'll find the iframe as an opener. Yeah, but this is not. Yusef, how? Yeah, so. That doesn't make any sense. It makes. So. Joel (01:20:20.934) I don't remember the details, but it's possible. Wow, dude, we got to... But it's not like something big that you can use unless there are some conditions for an attack to happen like that in a particular way. So in that case, you can... Wow. Yeah. Dude, that's crazy, man. I definitely want to do some more research into this and kind of... So there's this article that we've referenced a couple times on the podcast. It's called Every Known Way to Get References to Windows and JavaScript. We'll link it in the description for this episode, but it does a pretty good job. I don't think it's every single way. So do you know about the opener policy? No, talk to me about it. Yeah, so now with the browser, you can control if you want to keep the reference to the opener or not. I have seen this, yes, and you can do it in the, Something you do in the meta tag or is it a part of the? Metadata or in the headers, right? Okay. Yeah in headers. Yeah. Yeah, I guess in the headers. Yeah Cross-origin opener policy coupe. Oh coupe. Yeah. Okay. That's right. So that limited some of the Client-side attacks or these attacks Yeah, how are you going about finding? out about new stuff? Because there's like, I mean, the browser space especially is changing a lot, but even just separate from that, like the programs that you hack on a lot, how are you finding new features? Are you just sort of like watching their blog? Or how do you look for new stuff to hack on those same targets? And also like stay up to date about like browser level stuff at the same time? Yeah. So with browsers, it's basically they have like always discussions about like how to fix this, how to... So they're always discussing stuff and I always keep looking into them and I check origin trials for new features and browsers and go read about them. With Targets, it's about recon, so you have scripts in the background checking JavaScript files, downloading them and trying to find a new... Joel (01:22:40.43) code new stuff and if it's found, I just start working on it. Yeah, so actually that's a perfect transition. I wanted to talk about Recon. So I think you have a JavaScript monitoring sort of system that you've got, right? So can you talk a little bit about that and how that works and sort of how that plays into what we just talked about? Yeah, so basically, let's, for example, Facebook, they have like, an endpoint that would download react modules or return JavaScript files that include that module. So basically what I do, I just keep downloading JavaScript files, keep collecting module names, after that query that endpoint for more JavaScript files and keep the loop on. Also scraping pages like in Facebook for new module names and after that download the JavaScript files. So it's about collecting as much as possible. So it seems like so for me, just from a naive perspective, I'm looking at I'm looking at these whole JavaScript sort of packages that they have in a specific application as a holistic entity. and as individual, or not as individual modules and stuff like that inside. And I think I know of some hackers that do it a little bit more granularly. Okay, okay, this piece of code is a part of this library or this module, which is a part of this whole thing that's web-packed into this minified garbage that we all have to read. So I assume Facebook gives you this nice endpoint where you download the modules individually. But how do you, do you take that same approach when you're looking at different targets where it's like I'm separating out, okay, this module is a piece of this, and how do you parse this minify JavaScript to break apart all of these different modules and packages and stuff like that? Yeah, so with other targets like Facebook is too nice to have like, to keep the module names. Yeah. With the. Joel (01:24:51.298) other targets it's like obfuscated, the module name is random, sometimes it's just an ID or numbers. Yeah. So, actually we're gonna come back to, I'll let you finish, but I do wanna come back to Webpack lazy loaded things where they've got the, you know, 123 colon hash dot JS or whatever, but anyway, continue, yeah. Yeah, yeah, so I'll just focus on not the actual content of the function. I'll just... like let's say I'll give it a hash like that particular function with what it's doing now or it's contained now even if character is changed let's say variable name a, b, c like that doesn't matter and I'll give it a hash and that hash reference to that particular function now I'll just keep monitoring if that function was changed Is this minified code? Yes. Oh, interesting. So you're, if I understood it correctly, you're taking a specific function, you're hashing it. So are you doing like AST trees and breaking down the whole code structure? Yeah, onto functions. Dang, dude. Yeah, but it's not perfect, but it keeps me like with all the. like the hundreds of functions of all of that, I just keep some kind of reference that this function is actually maybe this function from an old version of that package. So that way I can like minimize the... false positives, yeah. False positives, I can look for new functions, a new code. Do you have an elegant way of dealing with variable names? Because I imagine if you hash a webpacked function, and then the next version, it's got variable names. But it might be the same function. Yeah, it depends on the target. So sometimes I just detect that they use single characters. Or for example, I'll... Joel (01:27:02.586) the arguments would be a, b, c, d, e, f, so that's fixed. But in the actual function itself, they'll use sometimes random characters. So I'll have different versions and different hash for different, if this was a, if this was b, if this was c. So it's not perfect, but it's just for comparison. after downloading this month's version This particular hash. Yeah, is it fun to try and reduce that attack surface down to something usable? Yeah, and okay So then do you do any of the hot AI stuff with it as well? Like do you run it through chat GPT or anything like that or is it is it just use of GPT? No, no, I use sometimes chat GPT to just like clear the code like Okay, can you Can you understand what's happening here? Just... Not by the way, but just... Like as code. With ChatGVT Currently I only use it Let's say as a programmer Not as a... security from a security perspective. So as a programmer, just clarify this code, clarify the names, variable names, make a sense of them. And that's it. And after that, I just do the security checks. I want to go back to that hashing thing you mentioned. So are you using AST to parse out like, because JavaScript has like... There's just like 15 bajillion ways to define functions and there's just a mess of syntax that you have to do. So are you using regex for this? Are you using syntax parsing? How are you doing this? So the only reason I'm doing this, for example, when the first thing I do after downloading the package is break it into functions or. Joel (01:29:06.71) parts so now with the new version I have of that package I want to make sure that this function is not like new I already checked it it's so I already have in the previous version hashes of that function with like even with the conditions that variable was changed to G that variable name was in Joel (01:29:37.925) of the function in the new package it's hash I check it in the previous ones if it's just found I just remove that function and focus on how are you extracting the functions though it's like minify and like with grip breaks and all. OK. So it's a Doing it via regular expressions. Yeah, yeah. Wow. That's a lot, man. There's some technology that I've been using, AST, which I think, do you know what it stands for off the top of your head, Joel? Abstract Syntax Trees. Yeah, so I keep on wanting to say AST Trees. OK, what's that? Abstract Syntax Tree. So it should just be abstract syntax trees. Essentially what it does, and this is how Jsluse, the tool that Tom Nom released, deals with this. And essentially what it does is it allows you to parse the grammar of those specific code base that you're dealing with. So I've done some automation with this with PHP. And you can also do this with JS where it will go through and say, okay, this is a function. Here's. give me all function definitions, and it'll query that whole code block for any function definitions. It's essentially, it's a programmatic way of parsing code. Right, so it's a job, like JavaScript has these built-in libraries that you give it a chunk of JavaScript code and it will return an object that you can then say, you know, what's the first variable definition? And if so, what's on the left side, what's on the right side? Variable name, value. And what's the name of this function? What line is it at? How big is it? And it will do all of that in like a Codified way so it's a lot more strict in terms of like it has to be valid JavaScript code It has to be able to validly parse it and understand it for it to get there, which it should be able to But it's yeah, I like that approach more like regex. I would always be worried that I'm missing stuff probably that's yeah, but Joel (01:31:34.934) Well, you know what you're looking for specifically because I have certain like, let's say, code or rejects for this target for this target. So I spend some time like with each target to basically have the Rory Conrite. And after that, I just forget it. This is exactly what we've been talking about is like, and I've actually spoken with some people in the critical thinking community about building this. And I kind of got about halfway through it myself and I haven't swung back around to it, but essentially building, instead of building a JS monitoring tool, building a JS monitoring framework, because at the end of the day, all of these scripts should be custom, because for each target, they're gonna have a different way that they're doing everything, and a different way of getting the files, and then you gotta unlazy load them, and then load them all in, and then JS beautify them, and then all the formats are different. So really, for each target, you've got individual things you should be looking at differently. And so I think that what we should do is build a Python package that makes monitoring these things a little bit easier and say, okay, you know, here's an HTML page, grab this specific script tag. Okay. Now you've got the script tab. Great. We've got an automatic, um, you know, D lazy loader that, you know, runs node on the inside and just, you know, dumps out all the values for these lazy loaded files and stuff like that. and then build a library surrounding that, and then we use that library to create specific automation for specific targets using these sort of tools. And it seems like that's what you've done. Yeah, but in the... It's for me, it's still a tool not framework. Like I do, yeah, it's not. You just run it once and it does everything at once or do you have different? Sorry. I did it. I imagine like I have just like a microphone attached to me at all times. So do you run it just like one and done and it does everything at once or do you have different? No, but I have to set it up. I need to do some manual work at first and after that. Per target? Joel (01:33:40.642) Portrait yeah, and after that set a few things and keep it working. Yeah, very cool It kind of reminds me of there's a couple different source map JavaScript source map unpacking tools that are like this because source map also it can be a little bit different per You know how it's how it's deployed or whatever and so sometimes you need to pull it from a different like Index on in an array or something like index one instead of index zero and one of the tools that I've used is it specifically allows you to configure, like I want it from this path on the AST, and it'll specifically do that. I think something like that, plus what Justin was talking about would be a good approach where you could say, for this target, the thing I'm looking for is here, and then you just feed it a blob, and it just parses it, pulls it out, and then you can just run that every single time until it changes. Yeah, I like that idea. Yeah, and I'll mention this, I haven't played around with this tool yet, but somebody in the Critical Thinkers, the premium chat for... for our Discord, released this, or posted this in here the other day. It's github.com slash middoxnet slash mapper plus. It seems like a, it says an advanced source map extractor based on a headless browser. And this is something that I thought about doing for a while using headless browser to actually do that source map abstraction easier. Yeah, yeah. And so I'm definitely gonna check this out after this. They dumped it on me right as I was about to go and do. a live hacking event, so I haven't had the chance to check it out yet. But I think there's a lot of innovation that could be done in the source map space. And obviously you've got... You won't say mine is the most innovative one. Yeah. Because, yeah, it's basic, but because I'm just looking for certain stuff. So after all, it's code. If I detect a pattern in the code, I just I don't need to fully understand it or reverse engineer it or... Yeah. No. And I think that shows... That shows expertise though, that shows that you know what you're looking for, which I think is very good. Just one second, Joel. The webpack lazy loading piece, obviously we've got tools like JSweasel that are kind of addressing this as well. Do you have your own piece of technology to go through and address those sort of lazy loaded pieces where it's like, you know, one, two, three, four, colon. Joel (01:36:03.326) hash and then it's dynamically creating that JS file. Do you know what I'm talking about or is it a little too abstract? Actually, I didn't like, like with the targets I work on, I don't usually see. They don't have that very often. Okay. It's so complicated. I mean, lazy loaded JavaScript is so annoying to hack on. Let me just do this though. Joel, I'm not even sure if you saw cause we've been knee deep in the live hacking event but I just released to the... to the Critical Thinker's Discord, the premium channel, a new, so I'll share this with you too, Yusef. I, and you'll have access to it after this anyway, because we give all the speakers access to the exclusive content, but, I've been trying to solve this problem of like, how do I programmatically extract lazy-loaded JavaScript for a while, right? And it's these functions that look like this, I'll turn it around, you can see it on the left-hand side, but it's these. you know, these numbers right here on the side and then the hash and then it automatically generates it. So for a while, the first version of the script that I did was using these crazy regex to like, parse out the number and the correlating the name and the hash and the number and the hash and it was just a whole cluster, right? And then I realized, oh shit, the function that has this defined in the JavaScript is actually a function designed to dynamically generate the name. So just all I had to do. was copy the function, put it in my script, run eval, and then pass every number that I see, and it just automatically generates. Yeah, you don't have to worry about that. Exactly, exactly. And so now we've got a very easy way to extract that using Node. And obviously in the browser, they're only gonna load the things that they need dynamically. But when we were doing recon, we want to have every access to every single JS file. So I released that script to the critical thinkers. We'll leave it as a task to the non-critical thinking listeners to go ahead and build that yourself. But it's been very helpful for me with recon and analysis, and I think it would be for other people as well. One other question that I had here, and then we'll kind of go into a little bit more of hacking methodology stuff. Joel (01:38:24.705) as we close is how do you deal with I guess how do you think about client-side routing in an application that you're looking at? Do you often go through there and try to enumerate all of the client-side routes that are associated with an application? And do you have any tips and tricks you use for this with various frameworks, or is it mostly just going in there, reading the code, putting in the time to understand where all those client-side routes are defined? Yeah, yeah, so I initially... try to understand how they define routes and everything. After that, I just- That's a pretty high priority for you in the beginning or? Yeah, at some point, not in the beginning. Okay. But at some point, I try to find routes and client-side routes, of course. And after that, I just... like extract all the list and review it manually. So it's mainly manual. Mainly manual process. Yeah, that's something that I'd also like to see, some innovation in the space. And I always like to mention this on the podcast because somebody's gonna get, some Joel-like person out there is gonna get triggered and have to go write this tool that parses like, yeah, you know, like React or, you know, all of these different frameworks have their own way of defining these client-side routes. And I think it'd be really cool to just kind of. have some sort of browser plug-in or some sort of tool that would show me exactly what code is being executed when I go to this specific route. And for this event, I can talk about it, you know, for this event, you know, there's this, for one of the targets, you visit a route, and then it's got like this whole weird stretch of JavaScript, and then it instantiates a class. So the first thing that really runs is like the constructor of this class associated with that specific route. Joel (01:40:16.414) And so, if that's a common thing, it'd be really cool to be able to link it to that class and would help with enumerating all these rather than having to set breakpoints and then work back. That's what I do. Is that what you do as well? Yeah. So I have to, it's like, to some point it's complicated. You have to find like the first lead and after that follow it to understand how it works. And you do it with the single route and after that you can do it to... Automated with all the routes. Yeah a lot a lot of it sounds like sort of that calibration that you're talking about where When you're starting on a new target like identifying What are the patterns how do they structure stuff? What are their routes look like? What a client side routes look like I noticed that a lot in mobile as well actually because mobile again lots of obfuscation same looking for patterns so you mentioned in your bug bounty reports explained interview that you wanted to do more like you know, mobile stuff and less web. Have you been doing that? Yeah, so I won't say I did more mobile than web, but I tried. So it was like a couple of, so I've been working with on OAuth for like, for the past few years, and I wanted to know how mobile handles that. So yeah, it was a research about like, Let's say you want to connect to a company using Facebook in mobile and how that is handled, how the communication between that company application with the Facebook application, how they start the intent with the parameters, how Facebook shakes these parameters and make the call. So I did the research on Facebook, like logging in with Facebook on mobile, and I found like a couple or three bags there. Awesome. How like they can verify how the application that requested the OAuth token of, let's say app ID equals one, how we can verify that application has the right to. Joel (01:42:37.758) access or to read that OAuth. They did some Android app signing and all of that. But at a certain point, they failed to, it's like a rare condition, they failed to have like, to pass the signature in the OAuth request or the signed Android key or something. they passed, they failed to pass it. And with that, if in the server side, if it receives a null key, it would just return the oath, like it would be successful. And yeah, but it's not like automatic. You need to allow, for example, let's say you're browsing any app. And a pop-up will show. Which app do you want to open this in? No, no. A pop-up will show do you authorize Instagram. Oh wow. Yeah, do you authorize Instagram application to access your account, let's say. Okay. You need to confirm, but when you confirm, you're not confirming the sharing of the OAuth token with the Instagram app, but with the attacker app. I see. So when you do that, when you're looking at these stuff, are you mainly looking at like, the meta-owned apps or are you looking at other apps that implement like Facebook login, for example, through OAuth? Yeah, because even other apps would use the SDK by Facebook, so it doesn't matter. I just focus on the main Facebook app and the SDK. Because they probably use the same. Yeah, yeah. They use their own SDK. Yeah, and the other back I found is like the race condition. I'm not sure it's zero day in, it's not. So they have a JavaScript bridge in WebView where you can... So they predefined some JavaScript functions that you can call from, let's say, target.com page in Facebook WebView. And target.com page can have the oath token, Joel (01:45:05.582) return to it from the bridge. From the bridge, yeah, right. So what I did, it's like a race condition where it verifies the document.domain or the window.location.ref. So I make a redirect and that redirect takes a lot of time and it would trick it into thinking that... It's it has reached that page. It's all come full circle. I mean, it's making me think about the thing we're talking about the beginning, right? Yeah, it's similar to the race condition. The other. Yeah, with caching. Yeah, yeah. But this one in mobile. So basically, yeah, you trick the bridge into thinking that the origin was changed, but it wasn't. Time to check versus time to use. Yeah, yeah. That's super, super interesting. That's awesome. I mean, race conditions on mobile. Usually don't surface himself in that way and it's such a it's such an interesting perspective to see like someone who's like such a JavaScript Like hacker come and attack mobile in like the same way and so much of it just still works. Yeah That's clutch man. I love anything relating to delayed You know responses HTTP responses that's really there's a couple scenarios in the browser as well where you can manipulate or you need to have a specific set of requests land in a specific order. And so I've used, now with, seems like cookie being default, all of these have to be top level navigations. So what I'll often do is submit a request into a different, a post request into a different tab, delay the response, and then eventually 307 it to a different location. And then in that meantime, have the original tab do a top level nav to a different endpoint. So you can get two top level navs off of one click, which is helpful in those scenarios. In this attack, like how I delete, I just make a post request, a post like redirect with a post request. So you set the target to self and make the body like five megabytes or something and it just... Joel (01:47:25.838) keep waiting, like it will take forever, yeah. Oh wow, interesting. Yeah, so, oh, but because, well, couldn't you also, oh no, because it has to be, what origin are you sending the message to? So, I don't recall. Yeah, but like, because if you're sending it to your own server, you could just do like a delayed HTTP response, right? And then 307. No, it's not, so what. Right. So what this will do, okay, it will try to send the post message to that page. Okay, but now I send the post request to the attacker page and would take a lot of time. So there is a point where it fails to check that the page has changed, but it didn't. Gotcha. Okay. I see why you're doing that. Once again, the massive body of the thing. The first page is still loaded and everything, but it thinks that the second, it actually redirected onto it. That makes sense. That makes sense. Wow. So many things from this episode that are just kind of spinning around in my head still. I do have a place I want to go next. Did you have something you wanted to say on that? I was just going to say the same thing. I mean, I wish I brought like a... had a sticky notes with me because I'm like I'm like sitting over here but I want it I'm like taking notes in my head and I'm like I need to write all these down when I'm done luckily we luckily yeah we've got the recording we got our boy our boy Brandon to grab me who's doing the hacker notes now so we'll get those there to you make sure you check those out by the way on blog critical thinking podcast.io you definitely need them for this episode because there's a lot of a lot of information I'm gonna have to get him this episode early because it's gonna take him a long time to parse out everything we said here. The last thing that I kinda wanted to go into here was you mentioned on your Bug Bounding Reports Explained interview, and I wanna also just take the time now to shout that interview out. If you enjoy this interview, you will most definitely enjoy that interview. So definitely check out Bug Bounding Reports Explained's interview with Youssef, really great content there. You mentioned on that interview that you use, am I, what? Joel (01:49:47.054) Yeah, get your water get your water you said come on. This is this is a chill thing He's he starts to reach for I said no don't drink it. I got a question answer quick you said No, you mentioned on that they use minimum MITM proxy I believe or maybe it's a different I couldn't hear what you said it kind of cut out right? Yeah, and So and you prefer to write your plugins in that Yeah, could you talk a little bit about? what you use that for a little bit more in depth because you mentioned on there, you know, there's something about secrets and that sort of thing, but I imagine you're looking for more specific things on specific targets or is it more generic things? And are you parsing JavaScript with that or are you looking at HTTP requests specifically? Yeah, so while I'm browsing in my browser, I'll use mainly meet and proxy and do an upstream to verb. And Metam proxy will basically save in time, like without delay, everything, HTML pages and JavaScript files and all of that, and start doing work on that. I don't need to wait for verb and after that, export it and export in that, all of that. So while I'm navigating the things, work is being done in the background. And what kind of things? Yeah, so mainly... Share the secret. This is critical thinking podcast here, Youssef. We don't just say we do things in the background. Come on. Yeah, so for example, it extracts a few things from the HTML page. Oh, did I hear things from the HTML? Yeah, yeah. Are we, are we, so we're, you know, you said from the HTML page, so I imagine, you know, this is, these are things specific to the current session, or... Yeah, to the current session. It's also basic recon. For example, endpoints mentioned in HTML, not in JavaScript. In JavaScript, it also gets all the endpoints and possibly sometimes the parameters used to the request to that endpoint. And it just shows them directly to me, and I'll just start testing. I don't need to do a. Joel (01:52:08.818) So it's basically scraping, but it's basically like having like headless Chrome. Yeah, it's like a scoped scraping because it's only for the stuff that you're proxying. Yeah, yeah. And then use burps in upstream, is that? Yeah, yeah, so I can still check things manually. That's cool, that's awesome. Do you use those like paths and stuff to create your own word lists? Or is that part of your recon flow at all? Or is it just? You look for the paths, you test the paths, and that's kind of it. Yeah, yeah, that's it. Got it, cool. Yeah, I've never really used Minimproxy. I'm not gonna lie. I've seen it used in a couple different places for like, especially hardware device proxying. I see a lot of people use it for that. What are the plugins written? Is it like bash or what is it? No, it's Python. It's Python? Oh, awesome, wow, look at that. Scripted changes HTTP and Python, that's pretty sick. It's like a verb, but in code, like you can... You can even, like at some point, I thought about having a graphical interface for it and use it as burp, but we have burp, so I... Exactly, yeah. No, there's definitely, there's things designed for that already. This is really interesting though, and I think this could be useful as well, now that Kaido has upstream stuff in place, is if you really need some sort of plug-in for your workflow, you could disjoin it from a specific... like burp or kaido or anything like that so you're able to be more flexible with your proxy GUI and Actually have you know this as a lower level thing Yeah, you're interacting directly with the file system and you know, I haven't used this at all But I'm just looking briefly over the docks right now and as I was prepping for this episode and it looks really Clean and simple. Yeah, and it gives you access to anything the request and the response and everything Like that's what you need man. All I need is a request object a response object, like it doesn't have to be that freaking complex, you know, and then just let me do something with that. So that's, uh, that's beautiful. I understand why you use that. And I think that's probably a great approach for any. And we've kind of talked about this on the pod as well. We need to now we need to disjoint any plugins that we're creating, um, from, uh, from burp and from kind of, because I, I Joel (01:54:29.558) And whichever arena you're in right now, there's no value in creating something for one when half of your environment is not gonna be able to use it. So I think using something, creating it for like something like MITM proxy could really allow you to just chain that right into the upstream and then disconnect from which proxy you're actually gonna be using and still have access to all these plugins. Hopefully, hopefully, Kaido's... Kiteo's plugin interface will come out soon though. That is something that I think they're very close to. So I think that's all I had as far as questions. Joel, did you have anything else before you wanted to, before we close it off? I mean, unless he wants to give me his social security number or something, I think I've asked everything. That's great. Well, Youssef, this has definitely been one of the most informative episodes we've ever had. So thank you so much for sharing your knowledge and all these different things and these awesome bug stories. I also have to say, I'm very impressed with your technical context window. and how much of these bug details you can remember, just sort of on the fly as we're talking about it. So yeah, thank you so much for coming on and for sharing all that. Thank you for having me and yeah, you're running a great show. Thank you, thank you. And I guess you're on Twitter, you're Samuda within zero, right? Instead of the, yeah. Yeah, and then do you have any other socials you wanna shout out? Yeah, just Twitter. Just Twitter. All right. Go follow him on Twitter, guys. And check out the blog to wisam.com. Oh, yeah, wisam.com. Yeah. Maybe we'll see some more blogs there sometime soon. Who knows? Maybe. All right. Thanks, man. Thank you. Joel (01:56:04.278) Joel, I'll let you do this because he's doing something. Dude, great interview, man. Thank you.