Episode 141: Hacking the Pod - Google Docs 0-day & React CreateElement Exploits with Nick Copi (7urb0)
Episode 141: In this episode of Critical Thinking - Bug Bounty Podcast Justin sits down with Nick Copi to talk about CSPT, React, CSS Injections and how Nick hacked the pod.
Follow us on twitter at: https://x.com/ctbbpodcast
Got any ideas and suggestions? Feel free to send us any feedback here: info@criticalthinkingpodcast.io
Shoutout to YTCracker for the awesome intro music!
====== Links ======
Follow your hosts Rhynorater and Rez0 on Twitter:
====== Ways to Support CTBBPodcast ======
Hop on the CTBB Discord at https://ctbb.show/discord!
We also do Discord subs at $25, $10, and $5 - premium subscribers get access to private masterclasses, exploits, tools, scripts, un-redacted bug reports, etc.
You can also find some hacker swag at https://ctbb.show/merch!
Today's Sponsor: ThreatLocker. Check out ThreatLocker DAC
https://www.criticalthinkingpodcast.io/tl-dac
Today’s Guest: https://x.com/7urb01
====== Resources ======
regexploit
https://github.com/doyensec/regexploit
Fontleak
debug(function)
https://developer.chrome.com/docs/devtools/console/utilities#debug-function
domloggerpp
https://github.com/kevin-mizu/domloggerpp
====== Timestamps ======
(00:00:00) Introduction
(00:02:40) Google Docs Bug and 7urb0 Introduction
(00:13:26) Bring-a-bug story
(00:20:21) 7urb0's DEFCON talk teaser & Intrusive Thoughts Worth Sharing
(00:30:01) CSPTs and React Apps
(00:51:31) CSS Injections
(01:04:55) 7urb0's backstory and game hacking
(01:18:33) Worst Crit
Title: Transcript - Thu, 25 Sep 2025 14:07:57 GMT
Date: Thu, 25 Sep 2025 14:07:57 GMT, Duration: [01:23:32.19]
[00:00:01.43] - Justin Gardner
So I thought it'd be funny to find a bug that made it hard to interact with the doc. Just, I wanted a client side DOS bug in a Google Doc because, I mean, it's a hacking podcast you send me.
[00:00:13.00] - Justin Gardner
Yeah, I sent you a doc.
[00:00:14.48] - Nick Copi
I should hack the doc. That'd be fun. Best part of hacking, when you can just, you know, critical things, right? Yeah, dude.
[00:00:39.46] - Justin Gardner
All right, hackers, we all know the value of a good misconfiguration, right? That's often how we're popping bugs and bug bounties. Well, unfortunately, threatlocker also knows about it, which is why they built DAC Defense Against Configurations. DAC scans all of the enterprise machines in your network for misconfigurations, ranks them by severity, and then shows them in nice graphics in a portal. It even emails your team weekly with updates, so nothing slips through the cracks. And the best part about dac, in my opinion, is that it actually maps all these misconfigurations onto security frameworks, and it also shows you how to fix them. That way, when you need ammo with leadership or with it, you can point to real specific compliance gaps and get actionable steps. Anyway, check out ThreatLocker DAC. It's an awesome way to stay ahead of these issues that we, as attackers, love. All right, let's go back to the show. All right, dude, Nick, demo, Turbo. What are we sticking with?
[00:01:28.68] - Nick Copi
I think we'll do Nick slash Turbo. I kind of cut my name over in the CTBB Discord slowly. So I did demos parentheses Turbo, then I switched to Turbo, parentheses Demo.
[00:01:39.48] - Justin Gardner
Nice.
[00:01:39.79] - Nick Copi
Now it's just Turbo. Hey.
[00:01:41.20] - Justin Gardner
There you go. All right, cool. You did make the transition.
[00:01:43.56] - Nick Copi
Eventually, yeah. I mean, the nickname, like, it's not like I changed my.
[00:01:47.40] - Justin Gardner
Yeah, so.
[00:01:50.12] - Nick Copi
Dude, it's in a better state.
[00:01:51.29] - Justin Gardner
You've been killing me ever since you got over here. So, listeners, for context, like, you know, Nick and I both live in the same city, and not even only in the same city, in the same little subsection of the same city. And it just pisses me the heck off that this guy. I can't say that I'm the best web hacker.
[00:02:11.49] - Nick Copi
I think you are.
[00:02:12.16] - Justin Gardner
No, I don't think so, man.
[00:02:13.37] - Nick Copi
You're selling yourself shortly.
[00:02:14.65] - Justin Gardner
I think so. Especially from the client side perspective.
[00:02:16.72] - Nick Copi
There's just so much client side stuff that you know about that I haven't touched. And it's like, I just haven't. I just don't have enough time and seat to have exploited that.
[00:02:25.40] - Justin Gardner
And it's because you're a bit Younger, right?
[00:02:26.93] - Nick Copi
Yeah, well, probably about four, I think four years. Because I think I would have started at VCU as you graduated.
[00:02:34.44] - Justin Gardner
Okay, all right, all right, well, we got. We. Before we get into too much of the history, we do have to, you know, you have to prove your worth to the critical thinking listeners by sharing a bug. Now I am actually going to share a bug before you do.
[00:02:49.55] - Nick Copi
Nice, nice.
[00:02:50.34] - Justin Gardner
Because this little twerp here, when I send him the doc to prep for this episode, he puts a bug inside of the Google Doc that makes it impossible for me to do anything. So first, why don't we start with that Nick and see where we go from there.
[00:03:06.11] - Nick Copi
I don't think I can speak about the details because, I mean, the report is still in a state where, I mean, they've not fixed it, it's not disclosed. I don't know how Google works with that. I don't know how much.
[00:03:17.56] - Justin Gardner
They're chill.
[00:03:18.56] - Nick Copi
They're chill.
[00:03:19.16] - Justin Gardner
Yeah. I would say just say the general details.
[00:03:21.28] - Nick Copi
All right, so there's.
[00:03:22.68] - Justin Gardner
You can cut it if they. I'll talk to Sam after. You can cut it if we need to.
[00:03:25.84] - Nick Copi
I like that.
[00:03:26.37] - Justin Gardner
Okay.
[00:03:26.84] - Nick Copi
Yeah, so there's functionality within Google Docs that allows you to do certain things. So there's rich context.
[00:03:35.12] - Justin Gardner
Okay, there we go.
[00:03:36.05] - Nick Copi
There's rich context. And so you can like embed things from other Google ecosystems. So I thought it'd be funny to find a bug that made it hard to interact with the doc. Just I wanted a client side DOS bug in a Google Doc because, I mean, it's a hacking podcast you send me.
[00:03:53.63] - Justin Gardner
Yeah, I said a doc.
[00:03:55.12] - Nick Copi
I should hack the doc. That'd be funny because I, you know, I know about bugs. I don't know about preparing for podcasts.
[00:04:00.84] - Justin Gardner
Exactly.
[00:04:01.43] - Nick Copi
So I'll prepare for the podcast by dropping a bug in here. So I did some dynamic client side instrumentation to look for inefficient regular expressions. And so I ended up finding. And it sucked because I wanted to use DOM Logger. But then when I tried to hook the function I wanted to hook, it broke DOM Logger plus plus because it called it internal. And so I should probably open an issue.
[00:04:25.85] - Justin Gardner
Yeah, we talked to Kevin about that.
[00:04:27.44] - Nick Copi
Yeah, well, the right answer is just open an issue, sit down and do it. But the problem is I'd have to do that.
[00:04:33.57] - Justin Gardner
Yeah, exactly. And you're here instead.
[00:04:35.42] - Nick Copi
Yeah, yeah. So, yeah, so instead I did something cursed where I just used Chrome DevTools, debug, shout out Jorian for putting. I mean, he put me onto That I know he talked about that on a past episode. That whole page is really good of the Chrome DevTools docs. It has some other interesting functions like monitor but so what I did is I set a debug on reg XP prototype exec refreshed the page so it hit the first one, just replaced that function with like a proxy wrapper call and then I had it create a set of each unique regular expression that it saw get called that way. And so this was like really naive testing. I didn't hit like reg XP test, I didn't hit string prototype match. I just picked one function and then I manually ran these sketchy looking ones through. So man, what's the tool? There's an open source tool for command line, regular expression solver for inefficient inputs.
[00:05:42.67] - Justin Gardner
Oh really?
[00:05:43.06] - Nick Copi
I forget what it's.
[00:05:43.94] - Justin Gardner
I've never heard of that.
[00:05:45.14] - Nick Copi
I guess I'll throw it a link somewhere. Maybe I linked it in here. No, I linked it in my report to Google. Well, because I walked through because I wanted to do the thing where it's a really good reporter at one point. So I walked through. Here's what I would do if I wanted to find more of these bugs and wrote exactly what but anyway, ultimately found an inefficient regular expression, found a source that reached it. The best part was the POC I built. So working with this, the way I was making the calls was kind of rough because man, the way that so kicks is the name of the Google Docs document viewer. The JavaScript is such a nightmare, man. And so I was modifying save updates via hooking the client side code with a conditional breakpoint. And so I'm like, well that's going to be really annoying to walk triage through dealing with. And so I'm like wait a minute, when you copy rich content it actually saves a bunch of stuff to your clipboard. And so what I ended up doing was figuring all that out and then just building a web page. What did I call it? There's some description in this dog vibe coded swaggy POC or something. So anyway, got it down to the point where you just like navigate to my site, click the button on the page, it copies the malicious crash Turbo badge to your clipboard and then you can just paste it in a doc. So that was good. The problem was if you did that, it would crash. They would hang as you're pasting it because they would. So I had to have them in the steps to reproduce defang the doc or they'd set a conditional breakpoint on that expression, just replacing it with something.
[00:07:27.50] - Justin Gardner
So it wouldn't be able to actually server side store because the client would.
[00:07:32.01] - Nick Copi
Hang before it could hang. So you had to instrument it. Which was good though, because I knew I could clean them out and I didn't have to do any additional work because I already had the setup and steps needed to do.
[00:07:42.18] - Justin Gardner
That's good. Yeah, man, that was hilarious. When I opened up the doc and I was like, oh my gosh, what is this? And it just crashed. That was pretty crazy. So I guess, you know, moving forward to future critical thinking guests, like, y'.
[00:07:58.06] - Nick Copi
All gotta up your game and bring.
[00:07:59.13] - Justin Gardner
It has been set.
[00:08:00.42] - Nick Copi
Yeah, that was a really lame bug. You've gotta put like, it's gotta escalate to the point somebody's just doing like full ATO payload.
[00:08:06.66] - Justin Gardner
Dude, if I, if I ever freaking open up the document and I just see an alert box on docs, dude, that'd be crazy.
[00:08:12.72] - Nick Copi
Yeah, well, actually, yeah, it'd be interesting if I'm not. All right, I've got a thought I'm not gonna get into. That would be an interesting way to have a modal appear on the page.
[00:08:23.04] - Justin Gardner
Yeah.
[00:08:23.68] - Nick Copi
And would be a lot less tricky in theory.
[00:08:27.07] - Justin Gardner
Yeah. Well, okay, hold on, hold on. So let, let's. But see, the problem is these pages all have coop, you know.
[00:08:32.72] - Nick Copi
Yes and no. This would be like a very low impact scenario.
[00:08:35.44] - Justin Gardner
Yeah, but.
[00:08:40.69] - Nick Copi
I'm not going to talk about it because I have to.
[00:08:43.33] - Justin Gardner
This is a good exercise. Let's go through this. But. Okay. No, Justin, I have to introduce the guest. I hear my dad's voice. Introduce the freaking guest, Justin. Guys, this is Nick, AKA Turbo. He also lives in Richmond, which is great. He's been a super active member of the critical thinking community. And as you can hear, he's kind of crazy with client side stuff. And so it's been a long time coming, man. You've been really active in the community and one of the first times you really, really came on the radar was when we're doing these hackalongs and just every single time we do the hack alongs, he's there and then just hands me something like, he's like, oh, here's a bug right away. And I'm like, dude, how are you finding this in like four seconds? Um, you know, and obviously with the hackalongs, it's like, it's like, you know, I. I'm having to do so many things besides actually hack that I'm much slower. But Even then I feel like, I don't know. The way you're ingesting these applications is really fast.
[00:09:42.46] - Nick Copi
It might appear that way to somebody busy trying to run the hack along. Like, like half of the time I'm off just doing my own side quests, not paying attention. Then I'll loop back in and be like, all right, yep, let's look at some JavaScript or something.
[00:09:55.72] - Justin Gardner
But, well, I've been really impressed and I would say as a, you know, self professed client side hacker, that Nick is like one of the go to guys and I'm pretty salty that I'm not the best client side hacker in Richmond right now.
[00:10:08.51] - Nick Copi
Not sure how real that is, but.
[00:10:09.96] - Justin Gardner
It means a lot, which is crazy. So, yeah, I guess from there we got a lot of places we could go. But I actually do kind of like that thought exercise of like, let's say we wanted to be, you know, we wanted to pull a prank on Justin. On the next critical thinking episode, you're queued up as a guest. You know, obviously the best way to get a modal to pop.
[00:10:29.73] - Nick Copi
Well, what qualifies as a modal?
[00:10:31.45] - Justin Gardner
Yeah, I think, I think any.
[00:10:32.76] - Nick Copi
What qualifies as a modal. And that's something that I don't even think that the browser vendors have agreement on. And I don't like, I don't know, I don't know if it's cool for.
[00:10:41.40] - Justin Gardner
Me to talk of, to talk about it, man. We could cut it out. This is the pod. Like, oh my God.
[00:10:46.49] - Nick Copi
Okay, well, okay, so if you make. There's an interesting observation that, well, what is a modal in your opinion, in a browser?
[00:10:56.46] - Justin Gardner
Yeah, so I mean there's, there's variance to that, right? You've got alert, you've got prompt, you know, you've got things like print. It's nuanced for sure. But like, to be honest, if, if the way that I would approach this whole Google Docs situation is see if I could hijack an iframe on the Google page, right? Like say they've got some sub resource that's got an iframe.
[00:11:20.71] - Nick Copi
I'm thinking something very similar and I'm.
[00:11:22.30] - Justin Gardner
Thinking like, maybe there's some third party that's in there that's doing analytics. I don't know, it's Google, so probably not. It's probably just Google, but that's doing analytics. You pop an XSS on that domain, now it's in a named frame and then you can do window open into the other frame.
[00:11:38.87] - Nick Copi
That'd be really Nice.
[00:11:39.83] - Justin Gardner
But I think coop is going to block you because your window reference is going to get severed.
[00:11:44.38] - Nick Copi
I wonder how many places you can frame docs.
[00:11:48.42] - Justin Gardner
Oh, you can frame docs everywhere.
[00:11:49.95] - Nick Copi
Really? Well, because if you can frame it somewhere without Coop then. Because it only cares about coop at the top level. You did a whole podcast about this.
[00:11:57.54] - Justin Gardner
Yeah, there is. Who did that podcast?
[00:11:59.62] - Nick Copi
Yeah. And so if you can find a. That's a useful gadget for, you know, whatever.
[00:12:04.35] - Justin Gardner
Yeah. I mean to be honest, I'd even accept if some, if a guest wanted to, you know, I frame the doc into a page and then pop, you know, a modal from within.
[00:12:14.11] - Nick Copi
So what I'm thinking of is if you just frame a resource and put it behind basic auth like www. Authenticate like that. Is that a modal? Is a basic auth.
[00:12:24.00] - Justin Gardner
Interesting.
[00:12:24.49] - Nick Copi
If you do like. I don't think it is injection. Is that like, is that a modal?
[00:12:29.61] - Justin Gardner
Is that a modal?
[00:12:30.28] - Nick Copi
And if it's. And I don't know, you know, I would say no in the eyes of browser vendors. No. Because otherwise if you set allow modal sandbox, then that should prevent it. But it doesn't.
[00:12:43.42] - Justin Gardner
It doesn't.
[00:12:43.90] - Nick Copi
I don't know if I'm supposed to say that.
[00:12:46.07] - Justin Gardner
All right, well that's interesting.
[00:12:48.30] - Nick Copi
I don't know. I don't know if. I don't know if that's gotta be known behavior by them. I think it is. I don't know. I don't know.
[00:12:53.11] - Justin Gardner
It is known behavior.
[00:12:53.99] - Nick Copi
Okay. Because in that case it's not a modal.
[00:12:56.54] - Justin Gardner
Yeah, that's a good point.
[00:12:58.54] - Nick Copi
Unless, you know, maybe some other browser vendor decides that.
[00:13:01.42] - Justin Gardner
I don't know what other pop ups are there. There's also like print.
[00:13:05.11] - Nick Copi
Yeah, I guess. I don't know. And then. Oh, the Google login thing. I don't really know.
[00:13:08.35] - Justin Gardner
That's what I was just about to say. Like if you can trigger.
[00:13:11.25] - Nick Copi
I just know that that's used for pop unders. But I don't know what it. Like I've never. I don't even know.
[00:13:14.97] - Justin Gardner
You don't have any control of that though.
[00:13:16.28] - Nick Copi
Okay. And I don't even know how to invoke that. Is it like Chrome.it's a Chrome API?
[00:13:20.37] - Justin Gardner
It's like a web API specifically.
[00:13:21.97] - Nick Copi
Okay. Yeah, I've never had to use that. Yeah, seems interesting.
[00:13:25.04] - Justin Gardner
It is pretty cool stuff. Okay, well that was a little fun. Little thought exercise. Sorry for anybody who doesn't love client side stuff because we're just going to like, we're Just going to geek out this whole podcast. You can just skip this one if you. But yeah, okay. So you also brought another bug though.
[00:13:41.33] - Nick Copi
Yes.
[00:13:42.12] - Justin Gardner
The one that. Not the one you left in my doc.
[00:13:44.04] - Nick Copi
A different one.
[00:13:44.92] - Justin Gardner
Yeah, here, let me see.
[00:13:46.69] - Nick Copi
Let's scroll. Because I actually wrote details about it this morning, which was crazy.
[00:13:49.88] - Justin Gardner
Ton of details about it. Let me go ahead and scroll up to it. Okay, so.
[00:13:55.25] - Nick Copi
Oh yeah.
[00:13:55.97] - Justin Gardner
Wow, this is pretty sick.
[00:13:59.09] - Nick Copi
Why does it. How does it have so many more red text than when I read it?
[00:14:03.09] - Justin Gardner
Because I've got Grammarly on.
[00:14:04.85] - Nick Copi
Oh, nice.
[00:14:05.52] - Justin Gardner
Yeah.
[00:14:06.37] - Nick Copi
Yeah. Okay.
[00:14:07.17] - Justin Gardner
All right, so hit us. What is this bug?
[00:14:09.22] - Nick Copi
So yeah, so I have to be vague about it. Basically I was hacking on a target that allows rendering user provided content in a scenario that is pretty cool and pretty high impact for XSS in that context because it's UI passive and wormable. Unfortunately they don't really care. Like they don't pay those out fairly. They pay them out as like a low high or something.
[00:14:36.07] - Justin Gardner
Oh really?
[00:14:37.35] - Nick Copi
I mean it's. What more do you want in this app?
[00:14:39.50] - Justin Gardner
Yeah.
[00:14:39.90] - Nick Copi
Anyway, so I decided that whenever I finally. Oh, and it was a react create element sync based bug. All of these were. Which are awesome.
[00:14:48.87] - Justin Gardner
Yeah.
[00:14:51.50] - Nick Copi
So I'd done one in this where man, it was crazy. But to establish some context for how I got to the bug I want to talk about. So I decided I wanted to escalate XSS on that to impact in the desktop app. So the desktop app's an Electron app. So yeah, so I'd done a lot of like auditing of the backend electron functionality of this. Quite a lot of interesting stuff. Supported a lot of ways that new web browsers or new browser windows got created dynamically. You could almost control the web preferences which if you could, you could set node integration true and then open one to attacker.com, and just. I mean that's free.
[00:15:32.65] - Justin Gardner
Yeah. Okay. Okay. So I'm not quite understanding. This is an Electron app.
[00:15:36.46] - Nick Copi
Yes, this is an Electron app to escalate Nexus and so couldn't get RCE that way because the goal is rce. So for a past bug I'd. They were using old Electron and so I was able to take Misty Mountain Cops V8 POCs for read, write, address of and just like slog through getting that into working Stager shellcode execution to grab a shell script. That was a crazy two weeks. It was. I mean it was like me using like I know how to use GDB and I know what's going on with. It was like Me doing native hacking on a browser application as if it's just a native app. And it was like. But I got it, I got things working. And I've written that up on my blog. I've done a talk on that. So that's not what I want to talk about. But I'd already been there with that. And so I'd found another create element based xss and I wanted to push it as far as I could with the client. So I was able to find functionality that let me persist the xss. So there's a way to open like a background window over the Electron IPC channel and you could point that at anything. And so in my case, I think only on origin stuff got the Electron IPC handler exposed to it. If only I had XSS on origin. And so I would just open a background window to a new instance that would spam Electron IPC updates to set the latest page visited. So whenever the app would reopen, it would read that and go back to the latest page you were on. And so I could just have it auto navigate to an XSS payload that would pop reopen a new background. And so I could persist the XSS within the client.
[00:17:16.22] - Justin Gardner
Okay.
[00:17:16.66] - Nick Copi
But I wanted to take it further. And so the Electron IPC channel actually supported quite a few sensitive things. So it could list processes, it could take screenshots on the client, it could take screenshots of Windows, and then it could take screenshots of. What do you call it on Windows? Not processes, but processes that have a window tied to them.
[00:17:42.02] - Justin Gardner
And so I don't know what those are called either.
[00:17:45.06] - Nick Copi
So you could get screen level screenshots and then you could get. Even if they don't have the same.
[00:17:50.43] - Justin Gardner
Thing with Chrome, where it's like, okay, Application Share Windows Application Share tab.
[00:17:54.82] - Nick Copi
Yeah, sure. Wonder why they had that functionality implemented.
[00:17:57.39] - Justin Gardner
Exactly.
[00:17:58.26] - Nick Copi
And so I tried to get key logging working as well, but I didn't because there was some other stuff, but I think it was too locked down to do that.
[00:18:04.10] - Justin Gardner
Okay.
[00:18:04.75] - Nick Copi
And so the final poc, I built like a whole site that it would call back to, like for command and control. And so it would not have scaled at all because I was like doing everything in real time with WebSockets, sending like base64 screenshot image data over a web socket. Because I'm like, I don't know, just build a psa. Yeah. So I have some screenshots in the dock of it that are censored and are really cool.
[00:18:25.93] - Justin Gardner
Yeah.
[00:18:26.25] - Nick Copi
And then I also implemented a functionality to be able to just have like a JS console and you can just run JS on the client authenticated as the victim.
[00:18:33.73] - Justin Gardner
So what is that old framework called?
[00:18:36.08] - Nick Copi
Beef.
[00:18:36.52] - Justin Gardner
Beef, Yeah.
[00:18:37.65] - Nick Copi
I don't know what Beef is up to, dude.
[00:18:39.56] - Justin Gardner
Like, that was crazy. Like, I think I say that old framework, like I feel like that was old when I was in college.
[00:18:44.71] - Nick Copi
Right. I've never used Beef. I don't know what it's about other than I've seen like. Yeah, what you're talking about.
[00:18:49.30] - Justin Gardner
I love the concept.
[00:18:50.19] - Nick Copi
Yeah, yeah. And it was really cool. And they did not pay it out as a crit.
[00:18:53.86] - Justin Gardner
No, dude. Well, hold on. How did you get. So I guess maybe we can, we can get to that as well. But how did you get the, the XSS in there in the first place?
[00:19:04.82] - Nick Copi
So, yeah, overly dynamic. So essentially they didn't do much sanitization of JSON used to render certain client side components.
[00:19:15.30] - Justin Gardner
Okay. So there's something coming back from the API.
[00:19:18.26] - Nick Copi
So you can store stuff with JSON and it gets. I mean you can basically. I'm going to say whatever you want, but not quite. I think they'd added a few mitigations by then just because I reported enough of these.
[00:19:27.67] - Justin Gardner
So it's a. It's a JSON to dom.
[00:19:30.26] - Nick Copi
Yes. And so what they do is they render these components client side. That. To be honest, I don't think those guys were expecting they would ever get rendered from arbitrary JSON. So they had certain values like a wrapper component and wrapper component props that you know, it's expecting like maybe some react component class as that maybe there's two of them that it uses. But when it's just using the deserialized JSON, you can just throw a string in there as the type. So you can throw like an iframe in there and then in the props you can just be like source JavaScript colon and boom, you've got an iframe. And so if you want to. Oh wait, that talk's not real. At the defcon Bug Bounty Village this year, I gave a workshop focused on that vector of XSS via React create element because it's a powerful sync.
[00:20:21.90] - Justin Gardner
Yeah, I would really like. So I know that you had that at defcon this year and I had to leave before then I had to go back and I missed that. So I think we need to do a re.
[00:20:34.50] - Nick Copi
Yes. Yeah, no, I agree.
[00:20:35.66] - Justin Gardner
And you know you said, I think there was some recording problem.
[00:20:39.05] - Nick Copi
Yeah, yeah. It like started a little late because they had stuff going on we were having a good time and so they just didn't record it.
[00:20:49.25] - Justin Gardner
Okay, all right, all right.
[00:20:50.50] - Nick Copi
So you what, torn up about it?
[00:20:51.85] - Justin Gardner
Well, we'll do, I mean, if you're down, if you're down again, we'll do maybe a CTVB version, Critical Thinkers or something like that.
[00:20:58.38] - Nick Copi
Yep.
[00:20:58.94] - Justin Gardner
Because I would really like to see the talk and I'm hoping, you know, today you can give us a little bit of a, a summary of that whole talk, or let's call it a teaser because we don't want to go into like too much of the, you know, nitty gritty because I know that that talk is really technically depthful and this is definitely not, you know, podcast medium is not the best for like super in depth client side stuff. But give me your, give me your teaser on that.
[00:21:25.46] - Nick Copi
Yeah. So essentially the premise is you'll have, I mean, well, there's React everywhere, you know, any next JS app everywhere, you'll have dynamic rendering of components with React. And so at the end of the day, when you're writing jsx, and this isn't necessarily as true as it used to be, that JSX gets compiled down into things that ultimately turn into react create element calls. Now this, there's. I have to put an asterisk there. Well, it's in newer versions. They actually do, I think like pretty fragment heavy stuff where it creates a bunch of react fragment wrappers and that reaches a create element or something. But unlike, I don't know, like react 18 or 16, I don't remember, it's direct create element calls. If you're just like creating a div or creating a component, it's more optimized. Now, I don't know the details. It's really complicated. The reality is you have this create element sync in React, not document, Create element. Don't confuse it with that. I'm not talking about that. But React has a create element function that essentially. I mean, I have a cheat sheet in here that's in the slides, but it takes three arguments. The first one is the type. And so that can be a react component class. That can be a react component function. That can be, man, it can be some other things that we're not going to worry about or it can just be a string. And if it's a string, it'll just use that as like the tag name.
[00:23:00.39] - Justin Gardner
Oh, wow.
[00:23:01.34] - Nick Copi
It takes props, which you can think of. That's what the props for the created component will be. But if it's a string tag, those will just be Attributes and certain ones have special values and are handled specially. So for example, dangerously set in our HTML, that's one that people think about the most there. So actually if you have props control and it's a childless component being created, you can just drop a dangerously set innerhtmlhtml in there. And so one of the lab challenges has a CSPT that reaches a create element sync in such a way where you look at it and it's not immediately clear that you can abuse that. It's really cool.
[00:23:44.90] - Justin Gardner
Is this specifically, is this most commonly exploited in scenarios where you've got some sort of abstraction on top of DOM elements that are being created? Like your JSON scenario? Yes.
[00:23:58.77] - Nick Copi
Yeah, A lot of the times, like.
[00:24:00.18] - Justin Gardner
A dashboard or something like that.
[00:24:02.14] - Nick Copi
That's a good. Yep. Yes, yes, yes. Ultimately, when you're thinking about what source do I have that's reaching this. My talk only really says hypothetically, let's say you have JSON data reaching this. Now, it could be more interesting than that. Like it could be. Maybe you have some. Oh man, this is curse. You have some post message listener that takes some data and you could use like structured cl, like instead of being JSON, it takes just like an object and then it's structured clone algorithm. That'd be weird. I don't know. That'd be interesting to think about. But that'd also be kind of cursed. But also maybe not. I could see. I could see how that could be.
[00:24:42.63] - Justin Gardner
I love this guy.
[00:24:43.75] - Nick Copi
Yeah, that could happen in the wild. I don't know.
[00:24:47.10] - Justin Gardner
Dude. I'll take this opportunity to just say that speaking of things that are cursed, this document that was prepped for this episode is the like takes the award for the most cursed document I have ever seen on critical thinking. Okay, let me just read to you guys a little bit here. Like not to say.
[00:25:04.99] - Nick Copi
No, no, go for it. And then I'll explain. This was the stuff that made it through.
[00:25:09.27] - Justin Gardner
Like, dude, yeah. And then in you hear, you're like, oh, this is the stuff that was triple the skills.
[00:25:13.92] - Nick Copi
Yes. So imagine what didn't even reach the dock. Like that's, that's the level I'm operating on. Like, it's insane.
[00:25:20.79] - Justin Gardner
Guys, for the listeners, I'm just going to read you some of these. Okay, here it is. He titled the section intrusive thoughts worth sharing. And he says, number one, hacking method. Hacking methodology. Letting the intrusive thoughts win. And then he puts, oops, I nuked the dock. And he says, fuzzing is really a form of agriculture. If you Think about it. Bug agriculture. Imagine. All right, check this out, dude. Imagine if you're a react use state setter Setter. Dude, I just like. It's like, what is. This is how you.
[00:25:53.80] - Nick Copi
Okay, so I'll explain the context.
[00:25:55.52] - Justin Gardner
Imagine you're a react use state set.
[00:25:57.73] - Nick Copi
I was playing with an application that used a 3. X version of JS YAML which if you use YAML load there it's like stupid dangerous. Now on 4. X it's not, but on 3. X you have to use safe load otherwise it'll do things like deserialize things as JavaScript functions.
[00:26:14.00] - Justin Gardner
Yeah.
[00:26:14.31] - Nick Copi
And so I just like threw a YAML file or just swaggy vibe code poc YAML file with a function that. So when it got parsed, instead of returning an object, it returned a function.
[00:26:23.31] - Justin Gardner
Okay.
[00:26:23.83] - Nick Copi
The front end executed that function. I'm like, why? Like, this doesn't make any sense. You're not going to just parse YAML and then execute it as a function. So the reason that happened is because it parsed the YAML and then passed it to a usestate setter in a React app. And so you'd think, okay, what's that going to do? That'll like store that state value for that React component as the value of the function, right? No. So usestate setters expect. And you can read the docs and get the exact language if they expect like a pure function. Well, if you give it a function it expects. Oh, okay. Instead of giving me some object or some like primitive to store as the state for this component value, it's a function that I'm supposed to call to get the state. And so that's how those thoughts. Because I'm like, what is going on here?
[00:27:13.74] - Justin Gardner
Sometimes it passes the value, but sometimes it also passes.
[00:27:16.18] - Nick Copi
If you, if you pass a use state set or a function, it'll be like, dude, I'm going to run that. And I'm like, why? It makes sense. It makes sense. And so that's how that one came to be.
[00:27:24.42] - Justin Gardner
Dude, that's correct. Crazy, man. Let me finish reading a couple of these. Another quote from the doc. The concept of small talk. But with an application, hacking is about watering those little mustard seeds of faith. Call it effing the application on the first day.
[00:27:41.60] - Nick Copi
Yeah, there's some interesting concepts there. The small talk with the application, that's a lot of like when you're like, I don't even know what's going on with this app right now. Like, I've tried a bunch of stuff On I'm just gonna, like, poke it these requests lightly when I have, like, a couple hours, like, not really expecting much to come off it.
[00:27:56.63] - Justin Gardner
Yeah.
[00:27:56.91] - Nick Copi
But then sometimes you're like, oh, crap, I just found, like, full read ssrf.
[00:28:00.99] - Justin Gardner
Yeah. You're doing. Doing that small talk. And then.
[00:28:03.50] - Nick Copi
Yeah. And it's like, oh, wait, yeah, yeah. And it's like, yeah. And you're like, whoa. So, yeah, that's a. That's how that concept. And then. Yeah, the other one. So the final one was around the concept of, like. Because I. I was like, looking at an app and I popped in exercise way too fast, and I don't even know how it worked. And I'm like, all right, what do I. What do I want to do with this app? And it's like, I'm like. I realized I'm, like, kind of working backwards here. It's like, wow, I already, like, went there with it and now I need to figure out. Now I need to get to know it and figure out how am I.
[00:28:28.59] - Justin Gardner
Going to show, like, effing on the first date. Dude, that's hilarious.
[00:28:33.00] - Nick Copi
That's how my mind works.
[00:28:34.11] - Justin Gardner
That's hilarious, though, because that's interesting. Like, it is a little bit more of a. Okay, exist now you've got full control of the situation. Yeah, yeah. And whereas a lot of times, you know, what we're doing is we're working backwards from the place where we're like, okay, so there's a token here, and this is the token that I want. How can I get the token? You know, can I get it via post message? Lee, Can I, like, you know, get it from a referrer? You know, do I need a full XSS to pull this out of local storage or whatever? Right. Yeah. Wow.
[00:29:03.45] - Nick Copi
Yeah.
[00:29:03.69] - Justin Gardner
All right.
[00:29:04.00] - Nick Copi
All right.
[00:29:04.32] - Justin Gardner
Nick, you're not totally crazy.
[00:29:06.08] - Nick Copi
Yeah.
[00:29:06.45] - Justin Gardner
You're not. You're not. You're not totally crazy. Okay, so coming back to the React Create element piece. Yeah, this is mostly a sync that we are looking for when we have some sort of serialized representation of the DOM that we need to reconstruct. Yeah.
[00:29:27.43] - Nick Copi
Really? Or something that influences it. I mean, it gets dangerous when you start spreading objects from JSON responses, especially if there's like, not if it's very loose, what can be there?
[00:29:38.25] - Justin Gardner
Do we need to control attributes? Like, if I'm looking at a JSON blob and I see something, you know, like. Yeah, I see an image URL and the key is source.
[00:29:48.14] - Nick Copi
Yeah.
[00:29:48.66] - Justin Gardner
You know, and I see like, another one that's like, alt.
[00:29:50.66] - Nick Copi
Yeah. Yeah, that would get you excited. You'd be like, okay, are they spreading this onto an image tag?
[00:29:55.29] - Justin Gardner
And if they are, are they just mapping it?
[00:29:57.50] - Nick Copi
Right. And then. Yeah, yeah, yeah, that can be interesting. Honestly, like, what I've been doing lately on react apps is when I have a cspt and I think I probably have a way to get some JSON in there, but I don't really know for sure and it's not a great way to test. But what I'll do is I'll actually dynamically instrument the dom, hook that fetch function, and tag every object nested recursively on the expected JSON response.
[00:30:28.20] - Justin Gardner
Okay, hold on, that's. We're going to double click into that real quick. Okay, so you've got a csp. The response of the CSP is coming back JSON. Let's say you have some way to control the JSON, whether it's like a upload media gadget or.
[00:30:41.98] - Nick Copi
I don't. And I'm like, I'll just find one.
[00:30:43.61] - Justin Gardner
And if I need one in your.
[00:30:45.66] - Nick Copi
Yeah, because I want to figure out if it's worth finding.
[00:30:47.50] - Justin Gardner
Well, I think that's a really great point. Is like, you know, do we go down and find the JSON upload, you know, gadget, or the open redirect, or are if we are trying to trigger this via CSP or are we just.
[00:30:58.50] - Nick Copi
Is there even anything to get. Like, is the CSP even exploitable? Is kind of the question. And so I would dig into that. Usually before looking for those, I would say, like, harder to find because, like, figuring out what's going on with the dom, that's all white box. You can just sit down and figure it out.
[00:31:14.58] - Justin Gardner
Right, Exactly.
[00:31:15.43] - Nick Copi
You'd hope. It might take some time, but. Yeah. So tell me.
[00:31:19.50] - Justin Gardner
So JSON comes back and then you're doing what?
[00:31:21.30] - Nick Copi
So I have. I do a sloppy check where I have a function that I call it. What I don't. I call it the tagger. So it tags that object. So any object on that response object, it adds like an XSS underscore tag string to maybe it'll include the path to that nested value as the string value.
[00:31:41.47] - Justin Gardner
Okay, how do you do. How the frick do you do that?
[00:31:43.43] - Nick Copi
Conditional breakpoint.
[00:31:44.54] - Justin Gardner
No, no, no. Like, are. Are you. Are you just taking the JSON? Like so, so let's say it does, you know, fetch dot then. Right? And then it does JSON and then it does. It does another callback and it uses the value. Yep. So right there in the. When it's using the value you just like, are you modifying the prototype for that specific. Like, are you just inserting into the objects recursively?
[00:32:09.03] - Nick Copi
Yes, I'm literally just adding string. I'm just adding. And this is not a great way to do this. This is a sloppy interest. I haven't ever had it work out either. It's going to though, one day, but, you know, and so I have that set there. So that object is tagged up and then I have a conditional breakpoint on the React create element function. So whatever minified webpack vendor code that ends up in, it's easy to find because everybody's calling it. Yeah, so just set a breakpoint somewhere that calls it. Just get a reference to it. It's the same one being called by everything. Look at the second argument and see if it has that XSS tag set on it. And so if it does, then that means some value from that JSON response allows me to add arbitrary properties that reach the props call. And so in cases where that's happening with like a childless component, you can slip the dangerously set innerhtml into that.
[00:33:02.16] - Justin Gardner
Okay, so. Okay, let me repeat this back to you, make sure I got it. So we do the cspt. We establish JSON control for every object recursively inside of that JSON.
[00:33:13.30] - Nick Copi
Yeah.
[00:33:13.67] - Justin Gardner
And so you add the underscore, underscore XSS or whatever, and then you do that by a conditional breakpoint. And then you set a breakpoint at React create element and you check the props that are being passed in and you do another conditional breakpoint, see if they're tainted to say, hey, if this has underscore under xss, then I have arbitrary prop control.
[00:33:32.02] - Nick Copi
Yes, in theory.
[00:33:33.30] - Justin Gardner
Okay. Yeah.
[00:33:34.54] - Nick Copi
And it's not great because, like, there's all kinds of things. If we had real taint tracking, wow, that'd be so great. But there's so many things that can break the tracking. And it might be the case with this, I'm just using like a stock intended value. There might be weird stuff that's supported on that though, that I miss with that. So there's like so many gaps, grabbing.
[00:33:52.80] - Justin Gardner
Something, cloning it, you know, like.
[00:33:54.80] - Nick Copi
And then sometimes it breaks intended functionality because there's stuff that like, cares about every key that's on there, and I just can't use this. And it's, it's a sloppy, lazy way to check.
[00:34:02.76] - Justin Gardner
But the whole, the whole concept behind it is good, which is that we need to try to figure out if JSON that's coming back is being arbitrarily mapped into attributes in a, in a react create element. And so assuming it is, let's just say we find one of those. Is it just as simple as adding like an onload event?
[00:34:24.01] - Nick Copi
No, you can't do that. How does this work? Right, so you can, if it is, child the cheat sheet and whatever, dude.
[00:34:33.73] - Justin Gardner
Okay, no, no, we can put it.
[00:34:34.90] - Nick Copi
If it's childless.
[00:34:35.82] - Justin Gardner
Hold on, hold on. Let me, let me, let me pull it up.
[00:34:37.82] - Nick Copi
If it's childless, you can use props.dangerously set innerhtml.underscore, underscore HTML.
[00:34:43.90] - Justin Gardner
Okay. Regardless, there it is right there. I don't know.
[00:34:47.21] - Nick Copi
I don't actually know. Yeah, I'm not sure. That might not work with certain types. I don't actually really know. And it might vary. I like the under construction gif. That was a nice touch on my part.
[00:35:01.32] - Justin Gardner
All right, let's.
[00:35:02.36] - Nick Copi
So we've got some interesting scenarios here. So if we control type and props, that's a really good day for us.
[00:35:08.84] - Justin Gardner
Okay, I see what this maps to. This is a mapping of what you control to what you can achieve with it.
[00:35:14.69] - Nick Copi
Yep. Okay, so types and props, that's just. And everything here assumes number one, deserialized JSON being passed into the function. And number two, we're not worried about CSPs, so we're saying types plus props equals XSS. So iframe with a source doc, have fun. You can just type iframe props source doc, I type plus children. So this one's actually interesting because I actually see a lot of, A lot of the times when you see dangerously set inner HTML syncs in code bases. It's used for styles, and it's like, oh, okay, you don't need to. If you pass a string child, it just. I don't understand. They don't need to. Maybe on older versions they needed to. But if you have type style children, some text nodes, it works fine. I tested it and it works because it's like I thought it wouldn't, but then I tested it because I wrote this. I'm like, wait a minute, that doesn't make any sense. Why do I see that everywhere? And it's like, whatever. So you know, style inline, style injection. That's pretty nice. Maybe we'll talk about that today.
[00:36:16.53] - Justin Gardner
Yeah, yeah, yeah. No, that's pretty solid. Okay, I see how these are mapping.
[00:36:21.73] - Nick Copi
Yeah.
[00:36:22.40] - Justin Gardner
Okay, so we need to establish. So all of these or most of these really are assuming you control the type of the object that's being created, though. Well, like iframe or something.
[00:36:32.00] - Nick Copi
Yeah, yeah, that's, that's like really a nice scenario. But if you don't support the type or don't control the type and there's no children present and I.
[00:36:40.48] - Justin Gardner
I think.
[00:36:40.92] - Nick Copi
It'Ll work on function type components, but I kind of want to double check that. Now you can set props dangerously set in our HTML. Underscore. Underscore HTML. There may be more.
[00:36:49.44] - Justin Gardner
So if you have arbitrary props control, you can also do that.
[00:36:52.15] - Nick Copi
Yes, but there's. With an asterisk. So number one, no children present, otherwise it'll throw an error.
[00:36:56.98] - Justin Gardner
Okay.
[00:36:57.34] - Nick Copi
So it, you know, because that makes sense because it's like what's the child of the element going to be? Is it going to be the children you provided or. That said.
[00:37:04.67] - Justin Gardner
Right.
[00:37:04.98] - Nick Copi
And it deserves to complain about that.
[00:37:06.67] - Justin Gardner
Yeah.
[00:37:07.30] - Nick Copi
And then I'm not sure how that fares with. I'm sure there's more asterisks. You could look at the REACT code.
[00:37:14.71] - Justin Gardner
But I mean it's, it's very solid research, you know, off the bat. And I love these graphics that. Richard, if it's not on the screen already, please put the cheat sheet up. But like I love these cheat sheets where we can say, okay, here's the primitive. So let me just condense it for the listener. Okay, the listener. The takeaway from this is that we need to try to identify scenarios where JSON or some sort of serialized version of HTML is being dumped into react create element in some capacity. And then there's various things that it could be being dumped into it with. It could be creating the, controlling the type or it could be controlling the props that are going into that specific type. And what this mapping here shows is, okay, if you control type and prop, then you can do this. If you control type in children, you can do this. And then maybe you only control specific set of props, then you can do this. And you've done the research, you've done the legwork for us to understand what's possible in those. And there's probably additional research.
[00:38:16.30] - Nick Copi
Yeah, there's. I mean there's so much missing here. Yeah. And some of this might not be. There might be more asterisks that belong here. And then I couldn't find a citation on the type plus children mixed case script filtering, which I tried too hard. Like I gave up.
[00:38:31.42] - Justin Gardner
Oh.
[00:38:31.82] - Nick Copi
Like, like I read, I read a write up about this like a year and a half ago, but I can't find anything on it.
[00:38:37.42] - Justin Gardner
Oh.
[00:38:37.75] - Nick Copi
And I was like looking, you know, like full, like Gemini deep research. And it's like, but I didn't hallucinate it. It's real. I'm not crazy. So maybe someone can help find that citation. And it sucks because I like, instead of going for the react versions here, I just did a rough estimate.
[00:38:54.53] - Justin Gardner
Old react, roughly 2,000. Yeah.
[00:38:55.90] - Nick Copi
And it sucks because it's like I really probably should have gone for the version, but I had to get the talk put together.
[00:39:00.26] - Justin Gardner
Yeah, no, no, it's all good, man. And that's why we had. That's one of the beautiful things about doing critical thinking podcasts is you can come on afterwards, talk about the nuances of it, you know, try to make.
[00:39:09.86] - Nick Copi
It someone else's problem.
[00:39:10.90] - Justin Gardner
Make it somebody else's problem. Exactly. Hand off some research. So we just got done with the episode with James Kettle. You know, one of the things that he is really great with is, you know, trying to give the community additional research topics to dive. Dive deep on. And the listeners just got done hearing about how they should do that. So give us the version of that for this. Like what, what kind of things would you like to see people go down the rabbit hole on for this, you know, reaction?
[00:39:39.71] - Nick Copi
Yeah. So the changes that have occurred between React 16 and React 19 for how this gets reached might be interesting because there are changes. It's very different. I don't know what's going on now. Most of my research on this was on I think 2018 version of react because that's just what the app was still using. Exploring that. The last item there is really interesting where if you control the children on older versions. So nowadays it uses like a symbol to tell if it's a react element or not. If an object's react element before it would just use like underscore is react component colon true or something.
[00:40:23.61] - Justin Gardner
Yeah.
[00:40:24.09] - Nick Copi
So there's a great write up you can find that is you can find a citation on that one. That one is real.
[00:40:28.34] - Justin Gardner
Dude, I've been screwed by that symbol thing so many times.
[00:40:31.30] - Nick Copi
Well, it's good. It's a good. Yeah, it's a good mitigation.
[00:40:33.61] - Justin Gardner
Yeah, yeah. Because like a lot of times I know when I. What I was trying to exploit was some post message based stuff and I was like, dude, I can completely recreate this object except for the symbol. And it's like just like find.
[00:40:44.26] - Nick Copi
What was this with Jason or was it with structured clone?
[00:40:47.00] - Justin Gardner
It was with JSON.
[00:40:48.07] - Nick Copi
Yeah, if it was structured clone, you should just find like a zero day that allows you to get symbols through structured clone. That'd be funny, dude.
[00:40:54.63] - Justin Gardner
That would be Crazy. Yeah.
[00:40:57.03] - Nick Copi
Yeah. So further research here. Yeah. Actually sitting down and becoming more intimately familiar with the life cycle of how components get created in react. So what happens after you reach that create element call and what the nuances of that are beyond. Wow. It made an element in the DOM with the type and attributes or it ran the render.
[00:41:16.40] - Justin Gardner
My understanding.
[00:41:17.05] - Nick Copi
Right. So I think getting deeper into that would be nice. I love. I'm sure there's interesting nuance.
[00:41:22.05] - Justin Gardner
I love it when you use the dumb voice and the double. The quotes and then say exactly what's going through my head. Oh, my gosh.
[00:41:31.76] - Nick Copi
Well, I don't know what's going on there, so I'm not any better than that.
[00:41:35.28] - Justin Gardner
Yeah.
[00:41:35.69] - Nick Copi
You know, you got to be deliberate about what you know.
[00:41:37.90] - Justin Gardner
Yeah, Yeah. I gotta be real about it. Um. All right, man. Well, good. Shit. I really was not. Did not have this on my radar. You know, a lot of times when I'm thinking about these sort of things, I'm just kind of using my CSP T to, like, spray for, like, any sort of actual, you know, real injection. And then if it's. If I did an H1 tag through, I'm like, all right, come on, that'd be a party react. Or is it. Or is it like, you know, oh, no, it's react sanitized. I'm screwed. You know? But I guess let's talk a little bit about CSP T, because you also share my passion for CSP T. They're cool. And one of the things that, I mean, there's been a lot of good research on it with resulting in CSRF and stuff like that. But one of the apps that I've hacked on recently has had a really interesting variety of CSP where there is a. A CSP that will occur when you are crafting the. Or when you first go to the page. So it's doing a get, it's fetching the object, that sort of thing. And then there's another CSPT that will occur after they interact with the page.
[00:42:42.01] - Nick Copi
I like that. Yeah. I was looking and thinking about one of those where the get isn't very meaningful. But if we could get a put or a delete on the same endpoint when you click a button on the page.
[00:42:52.82] - Justin Gardner
Yeah. So I guess one of the. That's the really cool thing about those. Right. Is like, you can prime the page and then the user's like, what the heck is going on with this?
[00:43:02.42] - Nick Copi
Do you want to chain that then with like a double click jack?
[00:43:05.51] - Justin Gardner
Yeah. Oh, my gosh. You could do that. You definitely could do that.
[00:43:08.98] - Nick Copi
I don't know. I'm not.
[00:43:09.75] - Justin Gardner
But I mean, it's. Most of the time it's doing a fetch, so you're not going to get it. I guess you could do a pop under and get it to preload, you know, because.
[00:43:16.90] - Nick Copi
Yeah, I don't understand your scenario. Do they have to perform some user interaction to get it to make those to the put?
[00:43:22.34] - Justin Gardner
So, you know, the first scenario is you load up the page, it loads an object right on the page, then you press save and it modifies that object. Yep.
[00:43:29.96] - Nick Copi
Yeah. Okay. Exactly. Yep.
[00:43:31.48] - Justin Gardner
So the way that I'm thinking about it right now is that there's only. I'm pretty sure this is not exploitable, but I wanted to get your thoughts on this. As if there are not differences in sources and sinks between the get and the state changing request, then I think you're screwed. Because, you know, if I wanted to, let's say I've got the CSP T, I've established it, I have full control of the path. I hit an or, I get it back to my server, I give it the JSON format that it's looking for. I create a fabricated object. It's like glitched or whatever. And the person says, oh, I need to delete this object. Okay. So they press delete on that. That generates a delete request that also has my CSPT in the. You know, in the path. Right. But it. I guess. Ooh.
[00:44:15.17] - Nick Copi
Yeah.
[00:44:15.48] - Justin Gardner
But if it hits.
[00:44:16.01] - Nick Copi
If it hits your server. Yeah. What are you going to. Are you going to redirect it to another. Yeah, but I don't know though, if that's gonna maintain authentication. It depends how they're doing off. If it's like, if it's. They're passing it via like an authorization header, then that's stripped.
[00:44:29.96] - Justin Gardner
It's gonna get stripped. But if they're doing if you 307 well, would it with cookies.
[00:44:35.51] - Nick Copi
I don't know, man. I should know that.
[00:44:37.32] - Justin Gardner
Dude, we should know that.
[00:44:38.19] - Nick Copi
Yeah. Come on. What are we doing here?
[00:44:39.76] - Justin Gardner
What are we doing on this podcast? Yeah, that's a great point because I was thinking like, oh, I'm screwed because I. Because in the situation that I'm hacking on, I don't have an open reader.
[00:44:47.96] - Nick Copi
Right.
[00:44:49.65] - Justin Gardner
But you know, and I was just going to do it by like a JSON upload sync.
[00:44:53.88] - Nick Copi
But could you modify those in real time, in between? So like as a low priv user, you like.
[00:44:59.48] - Justin Gardner
Yeah, but. But it's not.
[00:45:00.53] - Nick Copi
Okay, okay. It'd be Interesting.
[00:45:04.73] - Justin Gardner
The delete needs to be, you know.
[00:45:06.65] - Nick Copi
Pointed at, you know, can you modify the resource though? So like between the time that they've loaded the page, it's made the get the resources in one state. They.
[00:45:16.92] - Justin Gardner
You almost do like erase condition.
[00:45:18.36] - Nick Copi
Right. But then where's it going to go to? That's a good one. It's going to just hit the same stupid endpoint.
[00:45:23.15] - Justin Gardner
My favorite ones though are when you can get it to load up and then it actually takes an ID from the. From what you returned back and then puts that in the modified.
[00:45:33.07] - Nick Copi
That'd be cool.
[00:45:33.92] - Justin Gardner
And then you.
[00:45:34.51] - Nick Copi
That's really nice.
[00:45:35.28] - Justin Gardner
Then you can get like a delete.
[00:45:36.67] - Nick Copi
Right. Right post.
[00:45:38.59] - Justin Gardner
And then you get control over that. You know what I'm saying?
[00:45:41.40] - Nick Copi
Yeah. It's like having like an additional traversal for another request built into the first. That. That's nice. I wish I had that. Yeah. So you should just get an OR on that app.
[00:45:52.48] - Justin Gardner
I should get an OR take away and then, you know, Maybe use the 307s to actually see if that works. Yeah, we'll have to see, man.
[00:46:01.13] - Nick Copi
I should know that. I don't know. I think it, I think it might be a problem.
[00:46:04.80] - Justin Gardner
Yeah. Yeah. All right, well, let's, we'll, we'll think on that one a little bit more. Do you have any, any other. Before we transition away from this, do you have any other like thoughts on CSPT that, that you've been explaining lately? Because I know that you and I have kind of bonded over those in the past.
[00:46:22.19] - Nick Copi
I think that I don't exploit enough CSP T because I'm missing the gadgets to actually do anything with it. Yeah, like I have so much more CSPT than I have exploited CSP T because it's like whether it's, oh man, there's nothing fun going on here with what it's actually doing with the content or it's. There's no open redirects on this site until XSS Dr. And bus factor pop it.
[00:46:46.71] - Justin Gardner
And it's like, dude, I honestly, that made me so mad.
[00:46:50.92] - Nick Copi
I mean that write up was amazing. Okay, so the thing with like Bug Bounty that you don't get with ctf. Yes, it's an amazing csp. The thing with Bug Bounty you don't get with CTFS is when the CTF is over and you've spent all your time beating your head against a problem and you haven't solved it, somebody's going to publish a write up and you get to learn something with it. With Bug Bounty, you Just move on. It's like two years later. Right, Exactly. And so to have a situation where it's like, wow, I was looking at this the month before and so close. But there were, I mean there were really good pieces of that chain that I don't think I would have done. The way that they did the self dance was amazing. So even if I'd had, I had like the redirect. True, but for a different endpoint. And man, but the fact that you get to see the solution at the end, it's like you don't get that with Bug Bounty and that it was such a great write up that explained everything so well. And the bugs and those guys are brilliant.
[00:47:43.46] - Justin Gardner
They really are. Yeah. That was a, that was a beautiful piece. I think one of the interesting things that I've seen with CSP lately that I'll just tell you about is, is I found a endpoint where I could upload an arbitrary file, you know, that would be great for csp. I'm like, woohoo, this is gonna be great. But it's actually with it's application JSON content type, but the whole like file was just being returned as one JSON string. So like it was. The first character of the response was a double quote and then everything was quoted inside of it and then there was a, you know, a double quote at the end.
[00:48:18.86] - Nick Copi
So what content type was it?
[00:48:20.26] - Justin Gardner
And it was application JSON, you know, which is.
[00:48:22.78] - Nick Copi
Okay, okay, I guess that is valid JSON.
[00:48:24.50] - Justin Gardner
But you know what ended up happening? Dude, I was like, when I was, I was so gutted when I saw it. But what ended up happening was it was actually there was a recursive check that was saying like, hey, if this is a, if we can parse this as JSON, then parse it as JSON. So it actually ended up working anyway.
[00:48:42.13] - Nick Copi
Nice, nice. I love that. Yeah.
[00:48:43.61] - Justin Gardner
But those upload gadgets, you know, I think they are, they're definitely useful, they're definitely rare, but there might be more of them that I'm giving it credit for, you know?
[00:48:53.73] - Nick Copi
Yeah, yeah, it's definitely like if you're going to be doing csp, you've got to be good at then finding those additional gadgets that you need, whether it be an upload or an or or something. Crazy.
[00:49:05.90] - Justin Gardner
Yeah, that's why, I mean that's what the Doctor does, man. Like the guys like the Doctor and I was talking about last week, Tom Anthony, like just really putting in the freak.
[00:49:14.78] - Nick Copi
Oh man, that bug was crazy though. Yeah, that chain.
[00:49:17.82] - Justin Gardner
Yeah, that was beautiful. Actually, we did get permission to share a little bit more detail now on that. We mentioned it a little bit last week, but the way that it worked was. I'm sorry, Nick, I'm just going to yap about this now. I know you were in that chat too, but there was a window location replace that Tom controlled and then there was a window location replace that Tom didn't control. And they were right next to each other, right after each other. So the second one was just overriding Tom's exploit every single time. And what ended up. Actually the way that they ended up exploiting it was there is a same site limit on how many times you can do window location replace. It's like 200. So you find a. Say a same site or same. Yeah, same site. It was not same origin, it was same site. You find the same site location replace that you can trigger via on hash change or something like that. And then you turn that 199 times and then you redirect to your same site spot where you control the location replace. It hits yours. That's the 200th. And then the 200 first that would overwrite yours is over the limit so it doesn't trigger it. And then you get XSS via JavaScript URL.
[00:50:38.69] - Nick Copi
What I liked about this scenario was when you look at it intuitively, you're like, what do you mean it's not executing the JavaScript? This looks like this should do this. But it's like, no. Apparently however it decides to perform that replace. My whole thing was go read the browser source. Stop trying to do this black box. It's all white box. You can sit down and figure it out. I don't know what's going on.
[00:50:59.25] - Justin Gardner
Yeah.
[00:50:59.69] - Nick Copi
And I still don't know what's going on.
[00:51:01.09] - Justin Gardner
It was crazy. Yeah, it was very weird because you'd think if you did location, window location replace JavaScript URI alert and then window location. Replace whatever site.com then you'd get the alert first. But no, it overrides it.
[00:51:16.82] - Nick Copi
And I think that's why it was so cool because it's like you look at it and you're like, intuitively like, this should work. And it's like, oh, actually it doesn't. Here's a really strange browser quirk.
[00:51:24.38] - Justin Gardner
Crazy.
[00:51:25.73] - Nick Copi
And then abusing an even crazier man.
[00:51:28.09] - Justin Gardner
Yeah, that's freaking crazy journey. All right, man, so let's go ahead and talk a little bit about CSS injection stuff. You and I have also been on this crazy journey of what can we do with a CSS injection? I guess. Tell me a little bit about your journey. Do you have that bug in your head? In.
[00:51:51.90] - Nick Copi
I can talk about that in abstract terms. Don't remember the exact CSP requirements. Yeah, but essentially I had some scenario where some HTML is stored and reflected client side. It's supposed to be sanitized. They did like custom dompurify sanitization for styles where.
[00:52:11.82] - Justin Gardner
Oh wow, dang. That's kind of a crazy configuration.
[00:52:14.82] - Nick Copi
No, I mean, no, no, it wasn't. It was. You can. It just tries to wrap it in like a selector.
[00:52:21.57] - Justin Gardner
Oh, really?
[00:52:22.17] - Nick Copi
Oh, but you can just close the selector and be like, no, I'm not doing that today. So it was like cool.
[00:52:29.82] - Justin Gardner
And then, I mean, I'm surprised that they used Dung purify for that though.
[00:52:33.67] - Nick Copi
Well, because they also didn't want HTML in it. So it was like more bad HTML in it. Like they wanted some. It was for a scenario where you wanted some HTML, not bad HTML and you wanted the styles to not affect the whole page. So I don't. So they wrapped it in a selector and it wasn't really a security concern. I guess when. When the developer wrote it, they're probably like, you know, we want to be able to show these styles in the context of the content and so we'll just wrap it this way. And that's why they. But we want people to be able to write style tags and then have them only apply to the selected. You know, so. But yeah, you can just close it. CSP was a little bit tight. Could not do sequential import chaining due to.
[00:53:17.13] - Justin Gardner
That hurts the fact that you were.
[00:53:19.21] - Nick Copi
Either self for styles or you were unsafe inline. We were unsafe inline here. Limited character set or not character length. I think it was like, oh my gosh, 5,000 characters.
[00:53:32.21] - Justin Gardner
Okay, so still pretty liberal, but not enough.
[00:53:35.34] - Nick Copi
But the big thing it supported was data font URI and that made it exploitable with the static version of fontlake. And so fontlake is. I mean, I think it came out like a couple months before I was working on this, so I found the perfect time to be trying to do this exact scenario. So it's made by a Dragos. I don't know how that's pronounced. Romanian. CTF player. He has a great write up on it. You should definitely link it in the doc for this.
[00:54:04.34] - Justin Gardner
Yeah, I think we've mentioned it once or twice on the POD before.
[00:54:07.19] - Nick Copi
It's not really good. And so one of the things he built for it was static mode and.
[00:54:14.71] - Justin Gardner
I have not used this. This is interesting.
[00:54:16.32] - Nick Copi
Yes. And so with static mode, instead of doing sequential import chaining, it takes advantage of certain behaviors that you can use to cause. Using CSS animations to keyframes. Yeah. To resize an element and then trigger a new background load based on the widths. It's really big.
[00:54:39.19] - Justin Gardner
Yeah.
[00:54:40.00] - Nick Copi
It's not five megabytes. Oh, and I was trying to leak, like, there's a. So there's a style or a script tag in the header. I wanted to leak because it had a token. Dude, it's like a big token, too. It's like 1,400 characters.
[00:54:53.15] - Justin Gardner
Oh, no way. A massive token.
[00:54:54.94] - Nick Copi
Yes.
[00:54:55.19] - Justin Gardner
Oh, shit.
[00:54:55.59] - Nick Copi
And so I've got to leak a token that big with such a small payload. So is it.
[00:55:00.94] - Justin Gardner
Is it. Is this like a HTML injection like that? It's not via, like, post message or anything?
[00:55:05.38] - Nick Copi
HTML stored on the page? No. Post message. Yep. And so it's like you have now, if I had a css, If I could load CSS on origin, I had a way to do it, but it was prh, like, stupidly prh.
[00:55:21.17] - Justin Gardner
What is prh?
[00:55:23.13] - Nick Copi
Permissions required. High.
[00:55:24.36] - Justin Gardner
Oh, okay.
[00:55:25.05] - Nick Copi
And so I didn't want that. I don't know. I could have fallen back on that in theory if I really needed to.
[00:55:31.88] - Justin Gardner
Yeah.
[00:55:33.44] - Nick Copi
I wanted to fit it all within the 5,000 character payload. So I just generate like a naive one pointed at my domain slash function. You know, it's like 25 megabytes.
[00:55:43.46] - Justin Gardner
Oh, my God.
[00:55:44.73] - Nick Copi
So I have. Well, number one, I had to make so many changes, and I want to do a blog post on this and I was gonna. But I've been busy.
[00:55:52.42] - Justin Gardner
Yeah, do it, man.
[00:55:53.98] - Nick Copi
Yeah, but I've been busy. I've been on fire on some applications, so.
[00:55:57.46] - Justin Gardner
Have you really? Yes. Oh, my gosh, dude, that's the best. Well, you know the episode that came out last week? I don't know if you've.
[00:56:04.17] - Nick Copi
No. Cause the QA for it didn't come out. I was hoping the QA would drop today. I could listen to it before I came on and have thoughts about it.
[00:56:09.26] - Justin Gardner
Yeah, that'd be funny. Guys, there's like a. Some of you guys in the. Critical thinkers know this, but, like, there's a QA team for critical thinking where we have people get them early access to the episode so that they can review. And Nick has been a very, very loyal QA guy and has found lots of issues and provided really valuable.
[00:56:26.42] - Nick Copi
I like listening to the episode.
[00:56:27.59] - Justin Gardner
Really. It's the truth, man. It's freaking great. But yeah, that, that episode that we talked, we're actually launching the ctbb, you know, research.
[00:56:36.88] - Nick Copi
Yeah, one of the details on that. Because I'm always telling you guys that you guys got to drop something.
[00:56:40.88] - Justin Gardner
Yeah, well, we, we did the initial post and. Yeah, and, and so it is, it is, it is actually technically live right now, so you can go read it. But we're also going to open up the lab a little bit to the community and just try to give the community incentive to just write up because it is hard to write shit up, you know, and, and so, you know, we'll have a couple hundred dollars that we allocate to the lab each month where we can say, hey, you know, you did your write up, you know, we're going to host it, we're going to give you additional distribution, that sort of thing. Here's a couple hundred dollars so at least I can buy you dinner, you know, like that sort of thing. So, man, who knows? Maybe.
[00:57:19.48] - Nick Copi
Yeah, yeah, no, I have a couple.
[00:57:20.92] - Justin Gardner
Maybe drop it on there.
[00:57:22.36] - Nick Copi
But one of them is like pending cve. Whatever. What's the solution to this? So this right here. Oh man, I had to make. So number one fontly claims to support arbitrary parents of the. So you provide a selector for what you want to exfil from and it just exfils the content it's supposed to support exfilling from a head. It doesn't actually. Yeah, it doesn't actually do. So I had to change it and there was some nuances, but it is possible. Yeah, well, yeah, yeah, yeah. It's just like you had to like know what pieces of it to invert. So I just spent a while playing with it, trying to figure, talking to poor Adragos and just bothering him like having all these stupid questions that were like, man, this guy doesn't actually understand what's going on here because I can tell I'm asking him stupid and I feel bad for it, but I figured it out in the end enough to get it out all working. And so getting it X filling from a child of the head was one piece.
[00:58:18.44] - Justin Gardner
Using it all by keyframe animations in a sub 5000 length payload.
[00:58:23.23] - Nick Copi
Dude. Yeah. And so I had to break out the five letter domain.
[00:58:28.21] - Justin Gardner
Did you really say, well, it's a.
[00:58:30.13] - Nick Copi
Banger because it's pious but like elite.
[00:58:32.30] - Justin Gardner
No.
[00:58:32.65] - Nick Copi
Yeah, so that's a great domain. That is a good hacker handle.
[00:58:35.65] - Justin Gardner
That is.
[00:58:36.61] - Nick Copi
But yeah, had to break out the short domain because it needs to exfil to each one of those to step to the next state or whatever for, Man, I should have brushed up on this better.
[00:58:49.34] - Justin Gardner
Now you're getting. I know that, like, I also have exploited the same thing. We actually talked about it when you were exploiting it. And dude, it's. It's so bloody complex that because you were. You're like, oh, how did you solve this? I was like, look, dude, I know I have a solution to that, but I can't.
[00:59:03.07] - Nick Copi
I have it in a private git repo with my hacked version of fontlake. And so I changed all of the endpoints. So instead of like leaking on slash leak, I think it leaked on, like, just like, no slash. I changed, like, just literally just top. Just. I had to cut every bit, every bit for every bite I could.
[00:59:18.44] - Justin Gardner
Yeah.
[00:59:18.80] - Nick Copi
And so I changed, like, all the leak. I removed one of the prams that's used for like, tracking something that wasn't relevant. It's like. It was like stripping down a car. It's just like, imagine a Honda Civic with like no seats, no side panel.
[00:59:31.51] - Justin Gardner
You'Re just riding on the axle. Yeah.
[00:59:33.38] - Nick Copi
Just like weight reduction. But like. Yes. And so every queer parameter that was required was cut down to one character. I think I could have taken some of that further actually by. I don't know. Oh, I don't want to speculate on that.
[00:59:48.42] - Justin Gardner
It's all good.
[00:59:48.86] - Nick Copi
But that was one of the pieces. And then rewriting it. So it did just like. Was it ttf? Is that the uncompressed version?
[01:00:00.17] - Justin Gardner
Yeah.
[01:00:00.61] - Nick Copi
So it's a big font. It's a big custom font that gets generated by font leak. Yeah, By Adra. Because there's code and there's like. What's the compressed version? Is it OV wof?
[01:00:12.42] - Justin Gardner
What do you think?
[01:00:13.30] - Nick Copi
Yeah. Yeah. And so I had to rewrite it to auto compress the font for me because that saved space. It didn't save as much as I was hoping. And so I just had to keep sawing things off of this, rewriting things. And I also added UI so that triage could see what got leaked.
[01:00:29.23] - Justin Gardner
I'm sorry, I just. I just realized what you said earlier.
[01:00:33.42] - Nick Copi
Yeah.
[01:00:34.15] - Justin Gardner
This is done via a data URI in the font.
[01:00:36.86] - Nick Copi
Yes.
[01:00:37.51] - Justin Gardner
Oh, my gosh.
[01:00:39.59] - Nick Copi
Fortunately, there is no the image source CSP for actually leaking everything via the background float that let HTTPs through. So that could hit my short domain, Hit those, hit the font leak instance, hit all the. And so I barely got it all stripped down. It was not leaking the token reliably. I had to tune the rate at which the animation ran.
[01:01:01.48] - Justin Gardner
Yeah.
[01:01:01.96] - Nick Copi
I got it to Leak it perfectly if you just let it run for like three minutes without touching the mouse once. And I'm like, yeah, this is good enough.
[01:01:09.57] - Justin Gardner
Yeah.
[01:01:10.05] - Nick Copi
Well, because the problem is that there's a better method that a Dragos had using that was. I couldn't figure it out, man. I was just like. And I'd already spent so much time on it, I'm like, screw it. I'm just going to submit this as is if it gets through. I really think I proved this out.
[01:01:24.55] - Justin Gardner
The stuff is nuts. It like, dude, like, it takes so much time. Like, yeah. Dynamically generating the fonts and like.
[01:01:31.30] - Nick Copi
Well, fortunately, I mean, he did all the hard work.
[01:01:33.30] - Justin Gardner
I just hacked the hell out of CTF guys.
[01:01:36.71] - Nick Copi
Those guys are in that. Those guys are geniuses.
[01:01:39.88] - Justin Gardner
Like, yeah, yeah, dude. I think the keyframe piece is really good. And I think that as we continue to get more gadgets in css, this is going to get a lot more optimized.
[01:01:52.28] - Nick Copi
Yes. That's very exciting. And I. And I like when people in the CSS as a medium by which to express and create with people are like, browser devs. You should add things like nth letter selector. And it's like, you've got people that want to exfil over CSS that are like, nth letter selector.
[01:02:14.71] - Justin Gardner
I need this for my site.
[01:02:16.11] - Nick Copi
Yeah. And so I like when browser devs are encouraged to add fun features.
[01:02:22.84] - Justin Gardner
Yeah. I think one of the things that I kind of want to do, and maybe I'll put this on the Research Lab or whatever at some point is like, just create a list of things that would just solve everything, you know, in css. Like an N letter selector would be just massive, you know, or like. Yeah.
[01:02:38.05] - Nick Copi
There's really like two classes of CSS hacking too. There's like the stuff where it's just like, I know this selector and it's like, very straightforward. Then there's the stuff that it's like, I was able to get this element to change its size so this other element resized and that triggered. And it's like, it's like Minecraft Redstone.
[01:02:54.32] - Justin Gardner
Yeah.
[01:02:55.32] - Nick Copi
Css and it's being used to exfil stuff. And it's like, yeah, this is bonkers.
[01:02:59.53] - Justin Gardner
But I mean, I'm so glad that we do have the gadgets now to do it. Like for a while, not being able to leak contents of inner HTML sucked, you know, and now we have that.
[01:03:08.69] - Nick Copi
Yeah. It's crazy. Yeah. Yeah. And it's only going to get better.
[01:03:11.80] - Justin Gardner
Yeah. And I. Yeah. Can't believe that we can leave the contents of a script tag. How the heck can we style that? Like it doesn't disappoint.
[01:03:18.84] - Nick Copi
And with those CSP requor, I'm like, nah, there's no way. And I've actually posted it in the hacking channel and I was put on to font leak that way. So shout out the CTPPB discord. You should definitely join it. There's a lot of great discussions. There's a lot of bugs being escalated and, you know, scenarios being discussed where it's like, is this exploitable? And then somebody comments, probably Jorian, like, here's how you actually.
[01:03:43.55] - Justin Gardner
Oh my God. Yeah, yeah. And in the full time hunters guild as well. I think that's been a really valuable part.
[01:03:48.67] - Nick Copi
It's been amazing seeing how everybody's killing it, man. It's awesome.
[01:03:53.07] - Justin Gardner
Yeah, everyone's, you know, they're kind of like, a lot of times people are updating, hey, this is my monthly, you know, this is how much I earned, how much I hacked. You know, here. Here is where I am on my, you know, full time bug bounty journey as far as like burnout and like, trying to enjoy vacations and that sort of thing. And everyone can just kind of like commiserate together and that sort of thing. Yeah, it is quite lovely.
[01:04:13.67] - Nick Copi
Yeah, I've seen the victories. That's always thrilling. Just amazing. I mean, it's just amazing how much like volume for victory there is in bug bounty. And it's like, there's no, there's no limit to the success you can have with bug bounty.
[01:04:28.90] - Justin Gardner
Yeah. Dude. What a. What a beautiful industry.
[01:04:30.94] - Nick Copi
Yes, it's awesome.
[01:04:32.03] - Justin Gardner
So when are you. When are you going full time bug bounty, dude?
[01:04:34.78] - Nick Copi
Well, I can't speculate on that because I'm on a podcast right now. Maybe one day it's something I'll consider.
[01:04:43.26] - Justin Gardner
Really. Okay.
[01:04:44.11] - Nick Copi
We'll put it that way. I don't know. Um.
[01:04:47.65] - Justin Gardner
I think you'd crush it, dude. I think you'd crush it, but I mean, you're already crushing it, so it is what it is. Yeah.
[01:04:53.09] - Nick Copi
I really like my day job.
[01:04:54.69] - Justin Gardner
Yeah.
[01:04:55.05] - Nick Copi
Oh, yeah. We didn't even walk through my background.
[01:04:56.73] - Justin Gardner
Yeah, let's swing back over to that real quick. We did. We got distracted by a bunch of other stuff. Okay. So, yeah, I don't know about this format, man, that we do. You know, I think it's cool because it's like, all right, we get some of the meat up front with the bug stories and stuff like that, but.
[01:05:12.88] - Nick Copi
Like, you've got the voice of your Father. And you're being like, who the hell is this guy? You gotta introduce him.
[01:05:16.88] - Justin Gardner
Exactly. Introduce them. You know what's going on. Okay man, so give me a little bit of history about your hacking experience and I'll jump in wherever we cross over.
[01:05:28.15] - Nick Copi
Okay. So my joke is that I've been heralded from birth. So the old roguelike NetHack, that's part of the starting text. As a child I played Nethack and I always talked about making my own version. And so to do that you have to like write C. Yeah, yeah. And so that's the world we live in. So age 10, started writing awful Microsoft Small Basic because it's like easy IDE setup.
[01:05:55.15] - Justin Gardner
Yeah.
[01:05:55.90] - Nick Copi
Like easy language. You're a dumb kid. Figure it out, kid. And you know you can't 10 year olds, you can't teach them C. That's like not safe. It's not memory safe. Yeah. I mean there was some like old like Google AI image like three years ago, like there was a long time ago about like somebody asking for like C fundamentals and the response was like these are an advanced topic and given that you're under 18, I can't explain this. And it's like, oh man, I like, I don't know how the AI got.
[01:06:29.44] - Justin Gardner
It'S got like the, you know, the blurred text like filter dangerous content.
[01:06:35.48] - Nick Copi
Yeah. But yeah, so did that. I don't know. We're. I'm glad that I didn't get too deep into that and start getting into like visual basic or like.net because like.
[01:06:47.73] - Justin Gardner
That'S how I started actually was Visual Basic and it was not fun.
[01:06:51.05] - Nick Copi
Well, at least you went to Python after I did save.
[01:06:54.05] - Justin Gardner
I did. Dude.
[01:06:54.90] - Nick Copi
Well, fortunately instead of me building like WX Python apps or whatever.
[01:06:59.53] - Justin Gardner
Yeah.
[01:07:00.09] - Nick Copi
I was writing JavaScript, mostly HTML.
[01:07:02.34] - Justin Gardner
Don't call me out like that. WX Python was my stream.
[01:07:04.57] - Nick Copi
I did my research before I came on the phone.
[01:07:06.46] - Justin Gardner
Dude, what the heck? I just got wrecked.
[01:07:08.65] - Nick Copi
Yeah, I did.
[01:07:09.36] - Justin Gardner
That was like one of my first jobs. Was like oh my gosh.
[01:07:14.25] - Nick Copi
Yeah. So self taught a lot of HTML, a little bit of JavaScript by like 14, I got more proficient with it. Some web app hacking on a Rails app. Maybe. I don't know. But a lot of like, just like silly Chrome extensions. Like well you, when you were slinging WX Python apps, I was writing like crappy Chrome extensions that were just like mostly content script.
[01:07:37.86] - Justin Gardner
Dude, I cannot believe you call me out like that. Damn. Okay. Solid.
[01:07:44.26] - Nick Copi
Yeah. So yeah.
[01:07:45.15] - Justin Gardner
So then, so Chrome extensions, you know, you're doing some hacking stuff there.
[01:07:49.30] - Nick Copi
Yeah, games like HTML5, JavaScript, Canvas.
[01:07:54.75] - Justin Gardner
Yeah, Flash. I mentioned Flash.
[01:07:57.23] - Nick Copi
So age 16. Yeah, I did a lot of like Flash game reverse engineering slash hacking of highly obfuscated state of the art Flash games. A lot of fun. A lot of just like.
[01:08:07.88] - Justin Gardner
And were you like posting the. On forums or like.
[01:08:10.76] - Nick Copi
Yeah, yeah. You know, a lot of it was like really cool visuals for like, you know, like building custom weapons in the games and stuff. Oh, cool. And then it was like, you know, you got to keep your Kong hacks account alive by having like AOBs that like generated enough points to keep the account alive. I don't even know if that's still alive.
[01:08:29.78] - Justin Gardner
Dude. I have no idea what you're talking about.
[01:08:31.02] - Nick Copi
Okay, what are you talking about? Just like game hacker stuff, you know. I feel like Kong hacks was. Was. Is some like game cheat forum where you'd like post like cheat engine array a byte or you know, maybe you write a whole trainer or whatever and share that. That's kind of sketch and so I don't know, it was just. There was some discussion. It was mostly trash, but it was like.
[01:08:58.47] - Justin Gardner
It's interesting. You started in the game hacking world though. Are you. Are you like. Is that something you're still interested in? Like, you know, there are a lot of really good game targets in Bug Bounty, but I don't think I've seen you go after them a ton. You did a little bit.
[01:09:10.64] - Nick Copi
I was the. I don't want to discuss that in the context of this because it's kind of like, you know, you're talking about the. Whatever.
[01:09:20.17] - Justin Gardner
Yeah, it's.
[01:09:22.01] - Nick Copi
It's not really something I'm so focused on right now. Especially because a lot of those are. If it's the kind of game that pays well, it's probably not the kind of game I'm interested in.
[01:09:30.81] - Justin Gardner
Oh, really? Okay.
[01:09:31.68] - Nick Copi
Yeah, so it's not like I'm not gonna.
[01:09:33.25] - Justin Gardner
More of like a hobby. Right.
[01:09:34.72] - Nick Copi
I can't. I can't hack on Fortnite. I don't care about Fortnite. Yeah, like it's. I try to hack on it and.
[01:09:38.68] - Justin Gardner
It'S like I don't care about.
[01:09:41.52] - Nick Copi
Yeah. But yeah, I don't know. Yeah, that was an interesting.
[01:09:45.81] - Justin Gardner
That was your. That was your teen. So. Yeah, I mean, I guess at that time I would have been in college at VCU already.
[01:09:52.61] - Nick Copi
It's really easy if you take the age numbers. You just put a 20 at the start and that's the year.
[01:09:57.73] - Justin Gardner
Dude, were you born in 2000?
[01:09:59.34] - Nick Copi
But it saves me a lot of time on thinking. So instead of like knowing when anything was.
[01:10:03.73] - Justin Gardner
I can't believe you were born in 2000. Yeah, okay. Yeah, so I would have been, I would have been in, in college while you were doing that and I would have been writing WX Python like you said while you were doing that. So once you get into college, what's going on?
[01:10:24.52] - Nick Copi
We're going to go before college. That was my real, my real alma mater is the Chesterfield Technical Center.
[01:10:29.72] - Justin Gardner
Oh, is it really? Yeah.
[01:10:31.40] - Nick Copi
So Cisco Network Academy program, fantastic program. I mean amazing. So I'm still involved as an alumni years later. We had ton of alumni involvement then.
[01:10:41.44] - Justin Gardner
That's awesome.
[01:10:42.13] - Nick Copi
But like, I mean they just gear you up and get you ready for all kinds of certifications. They get you hooked up with all kinds of like cyber security competitions.
[01:10:51.56] - Justin Gardner
Yeah, also. Yeah.
[01:10:54.52] - Nick Copi
Oh man. I mean just having the team there and the energy which is with the boys just ready to.
[01:11:01.09] - Justin Gardner
I did, I did CCDC a little bit and that was really fun.
[01:11:04.56] - Nick Copi
Yes.
[01:11:05.27] - Justin Gardner
But I can't, I can't imagine doing that in high school. That would have been.
[01:11:09.14] - Nick Copi
Yes, it was, it was a hoot and holler.
[01:11:11.51] - Justin Gardner
That is one of the cons of being homeschooled is like I didn't, I've always thought about that, you know, technical center that a lot of my friends that were in public school were going to and I was like that that would be pretty sick.
[01:11:21.90] - Nick Copi
Yeah, I mean it was an amazing program. Still is. So yeah. Started doing like local CTF and like in person stuff. KimwanBest edu shout out. Got to get the plug. We haven't really competed in my. I guess we do RVA SEC monthly or not annually. Yeah. But yeah, so you know, geared up doing like Cisco Networking as well as like Comptia A+SEC+. Well, the SEC+ was additional.
[01:11:48.97] - Justin Gardner
What are your, what are your thoughts on those certs?
[01:11:51.28] - Nick Copi
Very like. Well, they've changed a lot since then.
[01:11:54.56] - Justin Gardner
Yeah.
[01:11:55.05] - Nick Copi
But very good if you're trying to get your foot in the door. I mean especially in the state of the industry now.
[01:12:01.05] - Justin Gardner
Like that's, that's kind of what I tell to people like, you know, if you're actually going to be. If you're trying to get a job in the industry, you know, if you're trying to get your foot in the door. Those. Or just catch up if you're not in a security program.
[01:12:15.18] - Nick Copi
Here's how I'll sell it. Those afforded me the ability to start at VCU and also start a part time Job working for. When I was doing. I was supposed to be doing it, but then ended up doing software development. Because that's just how it. When you can write code, they make you write code.
[01:12:31.06] - Justin Gardner
Yeah.
[01:12:31.42] - Nick Copi
For the school. So, like, you know, I'm doing that while, like, my buddy's, like, working for Jimmy John's. Exactly.
[01:12:37.89] - Justin Gardner
Dude.
[01:12:38.50] - Nick Copi
Busting his ass on a bike and, like, dealing with just city traffic and almost dying, and I'm like, oh, yeah, I'm in the basement writing code. It's cool, dude.
[01:12:46.77] - Justin Gardner
It's.
[01:12:47.02] - Nick Copi
So that. And that. That afforded me those opportunities then. Yeah. So did all kinds of things. And that pro. It was amazing. Like, it was two years, but it felt like so much longer.
[01:12:55.46] - Justin Gardner
Yeah.
[01:12:56.18] - Nick Copi
We hosted. Actually built a CTF event for a local nonprofit, which was awesome. We were in that for a few years until.
[01:13:02.77] - Justin Gardner
Covid Dang, dude.
[01:13:05.38] - Nick Copi
I would have met Tommy DeVos when I was in high school, so I would have been at, like, an RVA SEC Monthly. Happy Hours.
[01:13:11.61] - Justin Gardner
Yeah.
[01:13:12.34] - Nick Copi
Somewhere maybe in the West End or.
[01:13:14.10] - Justin Gardner
Yeah. Rich Stack or whatever.
[01:13:15.77] - Nick Copi
And he just showed up one day and just started saying all these things, and it's like, at first, you're like, wait a minute. Is any of this real? This guy seems a little crazy. It's like, oh, it's all, like, relatively real. That's insane.
[01:13:26.85] - Justin Gardner
Yeah. Dude. It's so funny that that's a part of your story as well, because there's so many top hackers that have somehow just had, like, a. A brush passing with Tommy. Right. Like. Like, so me zlz also, you got to get him on the POD cdl, you know, like, you. Like. It's crazy. He just. And it's not always a lot of involvement, you know, Like. Like, I've hit Tommy up from time to time and stuff like that, but we haven't hacked together very much. It's just that one day that he came into the cybersecurity club and was like, dude, bug Bounty is real. And here it is. And that was. I was done. I was cooked.
[01:14:03.17] - Nick Copi
Yeah. You know, he put Ali on.
[01:14:04.60] - Justin Gardner
Oh, yeah. Oh, yeah. Ali was. It was all over it, too. What a legend, man. What a fricking legend.
[01:14:10.93] - Nick Copi
Yep. And then. I don't know. Eventually I graduated high school. I missed my high school graduation, though, to go to RVA SEC conference. That was awesome.
[01:14:18.60] - Justin Gardner
Class. Um, Yeah, I can't.
[01:14:20.81] - Nick Copi
Maybe there were some other pieces I wanted to hit there. I don't know. It was cool.
[01:14:23.69] - Justin Gardner
Yeah.
[01:14:24.14] - Nick Copi
Um, and then. Yeah. Going to vcu. So I think part of the reason I went to vcu. Well, number one, they had a great offer for me.
[01:14:32.53] - Justin Gardner
Yeah.
[01:14:32.89] - Nick Copi
And then number two, it's local. And then number three, I met Irwin in the Cisco Networking Academy.
[01:14:38.61] - Justin Gardner
Oh, really?
[01:14:38.97] - Nick Copi
Yeah. And so, because he came back as a, an alumni.
[01:14:42.34] - Justin Gardner
Alumni. He was super big into the system. Goes up.
[01:14:45.22] - Nick Copi
Yes.
[01:14:45.59] - Justin Gardner
Yeah.
[01:14:45.94] - Nick Copi
Yes, she still is.
[01:14:47.43] - Justin Gardner
Yeah.
[01:14:48.98] - Nick Copi
But yeah, so he was able to get me into the Cyber Club. Get me. Just walked on to the CCDC team because he knew I was good.
[01:14:56.90] - Justin Gardner
Yeah.
[01:14:57.47] - Nick Copi
And, and it's not like we had, we had some, we had, we weren't.
[01:15:02.78] - Justin Gardner
Super stacked, if I remember correctly.
[01:15:04.51] - Nick Copi
Well, it was, it was like some, some schools have like an A team and then an entire B backup team, and we were not. But yeah, so that was cool. Going to vcu, working for vcu, doing. I think my job title at one point was Senior Software Development Technician.
[01:15:22.68] - Justin Gardner
Really? Wait, so you're working with vcu?
[01:15:25.64] - Nick Copi
Yeah, so I was working for labs and classroom computing in the basement of the library, hitting buttons. The manager was actually like an alumni of the Tech center program, maybe like 10 years before me. And they hired a lot of Tech center kids because they knew that they could like, do the work and were like, yeah, had the certs or whatever. And so that was all a great opportunity.
[01:15:45.21] - Justin Gardner
Did you, did you ever cross paths with Zephyr? Yeah, that's. Dude. Frickin Zephyr, man. I love that guy. Yeah. Dude. What a. So what a fun time. Yeah, the cybersecurity club, man, it was. I mean, I definitely couldn't have done that without, without Zephyr because we started it up and then some guy from the Linux department gifted us like this server rack and we just hauled it over east and just like shoved it in a corner. And then Zephyr's like, leave this to me.
[01:16:14.10] - Nick Copi
Yeah. Yeah. And it was sad though, because, like, man, there was kind of a battle where people wanted to move off of Proxmox onto ESXi. And I'm like, come on, man. So fortunately Zephyr helped hold it down.
[01:16:24.51] - Justin Gardner
There we go.
[01:16:25.31] - Nick Copi
Yeah, I don't know what ended up happening to all that, but I think they redid that room and moved the rack after covet everything.
[01:16:33.14] - Justin Gardner
I went back there not too long ago and it was gone and I was so sad.
[01:16:35.85] - Nick Copi
Yeah, well, the Cyber Club is, Is it really? I don't know what happened. Yeah, so essentially what happened was I. I don't know, I passed it off to someone after I graduated. And I think he was about to graduate though, after that. And then after That I don't know what happened, dude. But then somebody picked it back up. No, no, it's not okay. I've talked to Irwin about this. We're. We're going to do a little bit of a coup. So what happened was there was kind of a schism where the whatever club was going on was ineffective. They weren't meeting. I don't know. So another club formed and Fung left.
[01:17:08.39] - Justin Gardner
Oh, really?
[01:17:08.94] - Nick Copi
Yes. And so the club got taken over by someone. I don't. I don't know, whatever. So a second club formed called the cyber competitions club. And so the main club ended up dying and I think the cyber competitions. So what needs to happen is somebody needs to go to the cyber competitions club and tell them, hey, guys, you're the cybersecurity club now. It's back alive, the chain. That's what I think. And so, I mean, that's kind of.
[01:17:31.06] - Justin Gardner
What we did anyway. You know, we did. We did the competitions. And the way that I structured it in the beginning was just we met weekly. You know, somebody from the club would talk about, you know, some vulnerability, whether it be a web or like some meta solution or something, and that's how we would. We would do it.
[01:17:47.38] - Nick Copi
So it was. It was nice in person. When I took it over after Covid, man, people did not want to sit in one more zoom call. Yeah. And then it was hard to get. Like, sometimes we could get content and we had people that were really carrying, you know, good club members that would do stuff and. But sometimes it's just like, I need to have a meeting. I'm just going to ramble for an hour about whatever I'm working on.
[01:18:07.89] - Justin Gardner
Exactly. And it's like, that's what I do every week on the podcast.
[01:18:11.30] - Nick Copi
That's a good point. You seem to have mastered that.
[01:18:12.89] - Justin Gardner
I've done that. I've done that in college and also in my professional life. Speaking of which, we should probably move along from our vcu catch up.
[01:18:23.84] - Nick Copi
Yeah, I don't know if that's good or radio.
[01:18:25.07] - Justin Gardner
Yeah. Yeah. All right, dude, look, we've. We've run for a little bit here. Let me see if there's anything else on this list that I really wanted to get you to. Let's do one more. One more topic here. Do any of these. Any of these really stand out to you? This story about your worst critics. Pretty freaking good.
[01:18:40.84] - Nick Copi
Let's.
[01:18:41.15] - Justin Gardner
Let's wrap it up.
[01:18:41.76] - Nick Copi
Okay. Yeah. So you know, my first crit. Awful hard fought browser exploitation, figuring all that stuff out. My worst critic Was I'm looking at an app, looking at the checkout page because it's on like some separate origin.
[01:18:54.26] - Justin Gardner
You know, Glenn, like PCI isolated. Or is it like, you know, like.
[01:18:57.65] - Nick Copi
No, I'm like.
[01:18:58.97] - Justin Gardner
Or is the checkout page.
[01:19:00.10] - Nick Copi
It's like some subdomain field is like, yeah. Where they'll like do some cursed iframe stuff. Where technically it's. Yeah, no, this was its whole or own next JS app.
[01:19:09.22] - Justin Gardner
Okay, sure.
[01:19:10.02] - Nick Copi
And so I'm looking at it and I glance at the source and I'm like, oh, nice. My token's reflected in this. I'll take that down as a note in case I need a token week later. And I'm like, actually, let me. And it's a JSON web token. So I'm like, actually, let me grab my token from this and see what fields are in it. Cause it's like, let's see if I can inject into any of this based on like account creation details. That'd be cool. Let's just see what's even in here. So decode the token. I'm like, wait, that's not my email address. That's not.
[01:19:35.19] - Justin Gardner
No, no, no, no, no, no, no.
[01:19:37.27] - Nick Copi
Yes. And so I'm like, what is going on? Refresh the page, grab the token again. Wait, that's someone. That's a whole. And so what happened was they did have my token in there, but they also had someone. So somewhere in the next data that got returned for that page to render it, they cached stuff wrong, I guess. And so one of the sub objects would have some cached value that would include some random other users auth token. And so I was able to like grab one of those, hit like the slash, whatever slash me endpoint, validate that those were actually valid other people's tokens. And it's reported that they fixed it.
[01:20:21.05] - Justin Gardner
Pretty quickly, but depending on the cache lifetime too, that would have been.
[01:20:23.97] - Nick Copi
It was not. I refresh and I get a new token every time. And I don't like. So I don't know what the. How they messed that one up, but it had to be caching related with the next JS rendering something horribly cursed going on on the back end. I think they used a lot of kubernetes. I don't know. Yeah, what they were doing, I don't know.
[01:20:40.25] - Justin Gardner
Caching stuff is crazy, man. It really is all over the place.
[01:20:44.32] - Nick Copi
That was like such a free crit for like. And it's like, that's something that you're not going to pick up with like most automation either. Because you're not.
[01:20:53.60] - Justin Gardner
No.
[01:20:53.93] - Nick Copi
You're not expecting to be served 2 JSON web tokens in some JSON blob on the page.
[01:20:59.93] - Justin Gardner
Well, now I'm going to feel like every time I see a JSON web token, I have to like compulsively just double check that it is mine, you know, like instead of somebody else's.
[01:21:07.25] - Nick Copi
One of the interesting ideas I had in the document. Well, so some API security platforms.
[01:21:12.35] - Justin Gardner
Yeah.
[01:21:12.84] - Nick Copi
That are also that integrate with like API proxy. So I don't know. Let's just say Akamai.
[01:21:20.68] - Justin Gardner
Sure. Okay. All right.
[01:21:22.07] - Nick Copi
Let's just say Akamai and let's say no Name security their acquisition. They support like an API security functionality that allows for you to. Their system processes all of the web requests and then it. Based on requests that happened, it can actually try to pick up vulnerabilities in your code. Well, things that would be caused by your code or some configuration where it's like this is supposed to be authenticated based on the patterns we've seen, but it's not. I think something like that. But for Kaido history would be really cool. So something where you retroactively scan all of your requests with certain rules that look for things. So something like is some really weird email in a JSON web token could be something you retroactively scan all your.
[01:22:08.47] - Justin Gardner
For sure. And I just wrote down in my notes because I was hacking right before this episode and I was like, you know what I want to do right now? I have this active workflow in Kaido and I want to just run it on everything that I've done so far. And we're definitely going to make that happen at some point because.
[01:22:27.64] - Nick Copi
Yeah.
[01:22:27.84] - Justin Gardner
And then it just plop everything into findings and you're good to go. So I think that is definitely going to be something that happens. It's like passive workflow, but like retroactive, right?
[01:22:35.88] - Nick Copi
Yeah, yeah, yeah, yeah.
[01:22:37.88] - Justin Gardner
All right, man. Well, hey, thanks so much for coming on the pod. It's been a long time coming. Thanks for. Dude, it's just crazy because I messaged you. I was like, hey man, you're on your way over and you're like, I'm about to leave. And then like two minutes later you're at my house and I'm like, what the heck is going on? So. So it's great to have you around so close and I'm definitely going to hit you up whenever I've got some hacking problems. I'm just going to be like, hey, man. Just zip over, we'll shell some shit together.
[01:23:01.73] - Nick Copi
Sounds good.
[01:23:02.22] - Justin Gardner
All right, man.
[01:23:02.65] - Nick Copi
Cool, man.
[01:23:02.97] - Justin Gardner
All right, good. Pod as the pod. And that's a wrap on this episode of Critical Thinking. Thanks so much for watching to the end, y'. All. If you want more Critical Thinking content or if you want to support the show, head over to CTBB Show Discord. You can hop in the community. There's lots of great high level hacking discussion happening there. On top of the master classes, hack alongs, exclusive content and a full time hunters guild if you're a full time hunter. It's a great time, trust me. I'll see you there.