32-bit x86 LINUX BUFFER OVERFLOW (PicoCTF 2022 #31 'buffer-overflow1')

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello everyone and welcome back to another youtube video showcasing the pico ctf 2022 capture the flag and in this video we're diving into something new in the binary exploitation category finally diving into a buffer overflow let's get after it all right i'm gonna hop over to my computer screen i have sublime text open as i need it a kali linux terminal open inside of my kalalinx virtual machine but let's get to the challenge this is in the binary exploitation category and this might be the first challenge that we're starting to work on uh that has less than a thousand solves at the time recording so maybe we are in for a doozy here i guess i'm not quite sure yet again i'm still going in cold on all of these challenges so far let's see this is buffer overflow one our description is control the return address and it's also the first time we have a challenge instance or container it looks like that is launched on demand if we want to go ahead and click that launch instance button it will go ahead and start this thing up and i don't know how long this might take but all right looks like it's coming through we have apparently 30 minutes to solve this so goodness i guess we should get moving it says now we're cooking you can overflow the buffer and return to the flag function in this program you can view the source code here and you can connect to the remote service using this netcat command all right so we have a couple things to download let's go ahead and play with this locally and see what we can do here i'm going to move into the binary exploitation folder for us we'll make a directory for buffer overflow one in this case we'll hit enter w get this down and we have a vulnerable application oh where am i did i not even move into the buffer overflow one i did not all right so let's move our volume program into that and copy our cd into that directory i wanted to make sure i went into buffer overflow one rather than buffer overflow zero and there we go now we have a 32-bit linux executable link format or binary file with that said we could also download the source code so let's go ahead and grab that w get that down and that is just a simple c source code file but before we get cruising let's make sure we remember to mark our vulnerable program executable so i could dot slash and run it it says please enter your string i will of course say please subscribe and it says okay time to return fingers crossed we are jumping to this hex address um okay so let's open up vuln.c and get an understanding of how this actual program will run looks like we include what was an asm.h header file uh you can tell by the quotes here that would have been present on the original compiler like on the computer that was originally going to compile this code all these others with the greater their less than symbols those would have been standard libraries things that would just kind of come shipped with c and it's linker compiler and all that we end up defining some constants a buffer size and a flag size given that 64 characters in length and a win function being defined here as void so it will not return anything but it creates a character array the buffer the size of flag size being 64. opening up the flag.text file and then trying to read it if it's actually opened up if it isn't opened up if that file pointer or that handle isn't returned if it's just null then it tells you hey you need to go ahead and create the flag.text file your own local copy if you wanted to debug and test this on your own machine otherwise it'll read in the contents into the buffer and then print that out on the screen we have the vulnerable function which uses gets which as you might remember from our previous buffer overflow video is a very very dangerous function and it does not check for the bounds where it might end up being clobbering some other data that could be present on the stack now i've showcased buffer overflows in a lot of different videos i'll try and cover what i can here um but ultimately this is kind of going to be the lather rinse and repeat functionality of determining where and how can we overflow a buffer uh and cruise our way up to the uh return value that is stored on the stack right above a function stack frame or on part of a function stack frame as it's running inside of the program in memory so anyway we end up reading in our own input based off of a buffer size of buff size which is only 32 we know that we could overflow that hence the dangerous function that is gets and then it could tell us oh what even is the address that we might be going to and get return address i'm going to assume is a function that would have been included inside of that asm.h header file we can't see that in this function in this source code in this file itself but truthfully it would have been present in that that we don't have access to anyway the main function is pretty simple all it does is sets up the boilerplate main functionality for regular c program sets out uh i said a virtual buffer v buffer something that we can end up staging uh getting actual output inside of a socket or a remote service like we might access this with netcat just kind of boilerplate setting effective group ids so that we would probably be able to read the flag on the remote server an actual game server anyway it ultimately just says hey please enter your string put out onto the standard output and then we run the vulnerable function that will retrieve this because we are running the vulnerable function under and in through main we could actually break and overflow the von functions return address uh yeah does that make any sense let me let me make that a little bit more visual for you if i can can i google what a stack frame diagram looks like are there any good pictures of this thing it's always super hard to find one here they're showcasing it on 64-bit we're going to be using 32-bit but this might be a good way to represent it and here wikipedia is actually to our rescue talking about the calling conventions or the call stack in a stack data structure uh used in regular computer programs and c language and and this binary that we're getting into specifically where is that picture i want to help visualize this here it is okay so hear me out we'll get super close there's this thing called the stack and it is a representation of memory and what your computer is going to be juggling and carrying data as it is working through executing a program letting an application run and do its thing now you know as we've been exploring lots of source code and that you define lots of different procedures or subroutines for your code and your program to do to perform those are those functions right your program can execute functions and you've defined those with a def function we've seen in python specifically we've seen them in java with void static public etc we've seen them in c of course with everything that we just read through in the source code now whenever your computer moves into running a function within a program it creates a stack frame and okay we have an encapsulated box or a picture a picture frame really that is how it might reference data and information used throughout that stack frame throughout that function and there are a couple interesting tidbits in here let me show you that right so in this example let's say we were executing a function called draw line and while the stack frame is kind of put together in this building block diagram there are a couple different things that are pointing towards what it might look like and what it might be doing on and in that stack frame i don't know why just detected in a usb drive whatever with the stack pointer right something just kind of pointing at hey where are things currently on the stack uh could it be able to reference and determine what data is going to end up being used what's going on what data is being used for a function all right maybe this is going to be a problem i'm just going to have to let that go to that virtual machine if it's going to keep interrupting me like that you could use that stack frame base pointer to refer to local variables that are going to be used within the draw square function or even the parameters that were passed to that draw square or draw line function that would have been used alongside that as part of the stack frame it also keeps track of the return address now the return address is how your program knows that it can go back to where it was in the regular program execution after that function is complete that makes sense right in our procedural code when we would define functions over here and we called them in another function sure we'd momentarily go run that function and then go back to where we were executing the previous code the way that it keeps track of that is by storing the memory address of the location to go back to on the stack or inside that stack frame box now interesting thing though is that the variables that might be used inside of this stack frame and inside of the function right are bound to the size constraints that are allocated for them you know that and that oh we've defined a 32 character long buffer or a 64 character long buffer however with the function like gets as you saw earlier you could very well keep putting data inside of that buffer and if it's not checking those bounds the upper and lower limits right especially the upper limit you could break through that and start to overflow data on the stack in which case it'll actually pour over and clobber sensitive information like other variables or the return address now the return address is something very very interesting because once your com once your function is done running and it wants to bounce back and go follow that return address it's moving the instruction pointer to go tell the program hey go back to what you were doing earlier but if you could control that you can control what code the program runs next in other words you can control the program and that is how you can perform that binary exploitation and really make it hey run shell code or do something like cat a flag or open up a socket or a port to be able to get new connections in and out or disable antivirus or do whatever shenanigans you might want it's a little bit harder in more modern security stacks right a lot of modern mitigations don't normally allow a lot of this sort of behavior trying to clobber the return address is something that could be caught by something like stack canaries trying to execute shell code off of the stack isn't allowed with things like dep the data execution prevention or or nx the non-executable set uh or bit being set for memory and i know that's a lot of words and i'm super duper sorry for rambling for so long but i hope that gives you for one thing a little bit of a better visual and the idea that what a buffer overflow really is is it's hey pouring water into a cup so much so that you have so much water that the lid or the cover overflows and pops off and now you might be able to do more damage with hey what liquid what what beverage was originally inside of that cup you know super weird analogy i don't know but i hope that helps you define it and visualize it in a way the stack is something that you are taking advantage of for a stack based buffer overflow when you're clobbering that return address by overflowing data and reaching up to break it now going back to our specific example in the program here how could we control the program by modifying the return address and go to this specific function win that would tell us the flag otherwise that's never actually ran by our program naturally but it exists within the binary it exists in the program it's something that could be something that could be executed if we could control this instruction pointer so let's figure out what we could do uh by experimenting with that we know okay we could send data to our vulnerable function by supplying it as a string we knew that hey okay it would take 32 characters of input but could we give it more than that could we break through that let me end up creating uh probably just some simple python code and i'll make another terminal over here on the side where i could take the letter a sure but multiply it out 32 times and now i know okay that specific length might make the program do something strange let me enter that no i'm not doing anything different because we're at the limit we're at the we're at the end of it that buffer allocated for our input but say that is something that's going to be the very very first variable defined inside of this vulnerable function now if we were to keep climbing and we push more data onto the stack or get more data input all of these things in a 32-bit architecture which is the architecture of the program that we're working with those are all values and information and data stored in sets of four bytes or a d-word value and what i mean by that is like hey you might have seen hexadecimal stuff like 0x dead beef just an example 0x representing this is an hex but all that really is is a couple bytes being represented in different ways we just took four bytes and one byte being one specific set of two letters or two characters and cramming it all together to be four bytes d e a d b e e f so if we knew on the stack above our specific uh variable like our buffer was there what is going to be 4 just beyond that if i were to multiply 32 times a or a times 32 but also add 4 to that so i'm really multiplying it to 36 does that give me anything different let's try it not yet okay did i clobber anything there or were there bounds in the way it's worth experimenting with let's try and crank it up even more let's add another set of four in there so we're going to now 40 as the length of our a values to try and spam this thing make it choke give it too much data that it overflows so that causes a segmentation fault you might notice and it's an interesting thing did we break it some way somehow um if you can you could use a program like d message within your computer or within your linux virtual machine or operating system in linux you might be running and you'll need to use sudo permissions to be able to actually read this data out but at the very very bottom here you'll notice there's an error message that we got a seg fault or a segmentation fault that means the program did crash it died it broke it choked and it actually has zero for the current instruction pointer um kind of odd kind of interesting right why would that be well keep in mind hey we actually had a big long string but it is a c style string as it's a low level string stored within memory so the way that that programming language c and the low-level memory stuff will denote the end of a string variable is it will add a null byte character to it and that nullbyte is the 0x00 sometimes represented in the backslash x representation of 0 0 actually might just be slash 0 in some renditions and you might see it in different code and scripting language or programming languages sorry so zero of course if it were to be interpreted as the null by if it were to be interpreted as a number or like an address it's still just zero right so could we then know okay we have filled up to the point where just the trailing and ending null byte is getting pushed into that return address or instruction pointer placeholder let's try and see what we might do if we gave it another four bytes or another d word value i know i'm adding oh what four four four in here i'm just trying to find that sweet spot where we might be able to make this program crash let's use tac volun again supply our input string and it's jump into something weird or different this time we also see our segmentation fault let's check d message one more time and now let's put me at a weird spot hmm did i do something wrong i'm not quite sure let's keep experimenting let's add another four and see if we can get anything that's more reliable here i'll use vol slap in four of them oh you see something there our jump address return value changed into something completely different from the values that we were receiving previously previously it was just like uh zero x eight zero four nine three two four blah blah blah uh but now we'll jump to four one four one four which some of you smart people might notice and recognize is actually the hexadecimal value for the a character right now python is going to return the ordinal value of this a character in its ascii representation but if we were to take the hex value of that because that is just in decimal right python's going to want to tell us to in base 10 but our computers and the bytes are storing that in base 16 hex 41. so we just saw ourselves clobber that instruction pointer that return address so we really we clobbered the return address and now we can control the instruction pointer and we can make it jump to any address that we might like let me show you that one more time and let's get the d message uh value in there uh i'll grab this big long payload slap it in and let's check out sudo d message nice see how this has a seg fault at four one four one four one four one as the instruction pointer as i p that means we can control where our program is going to go next now where do we go right we know we want to call the win function um but where is that within our binary it is something that has been compiled into the binary and it's part of it so maybe we could determine where it is by using some other neat tools there's a really good tool you could use called read elf uh should be something kind of known on linux and common and built in you could pass in the file or the elf binary that you want to get some information on now if i hit enter on this it kind of wants to know okay what are you going to do with this what other options might you want to retrieve out of this you could use like hey tell me everything that you know or i just want to see the file headers the program headers section headers etc etc something really good to look at are these symbols because if the binary isn't stripped as in hey the symbols were removed at compile time this one is not stripped so just for our sake of learning for our education sake we could actually tell where are what functions in the binary let me show you that let's use read elf attack s to retrieve those symbols from vuln and now there's a lot here i know this is kind of dumped out but you could see some things and all over the place between different sections between different uh objects that it saw or files that it might have loaded as needed you also might notice some of these funk things this is this is the the column that i'm looking at very very sorry should have been more explicit about that uh but notice you could see there is our funk for the vuln function you also might be able to scroll down and find oh i see the funk address for the win function and over on the left hand side it tells us it shows us what the hexadecimal address for that function call is kind of cool right so we can actually use that we know okay that's where we're going to end up passing this and telling the program to go next but let me show you something i know it's kind of odd we were using this vol thing and adding in what was hey a's and actually the last four were what we knew were a instruction pointer clobbering right so let me grab bbb here and i'll actually just note this as a comment so i don't still have it in my clipboard i'm using bbb as the example hey this is where we control the instruction pointer by clobbering the return address but if we try to add in zero eight zero four nine etc etc uh it's not just going to be tacked on as a string right because this is obviously longer than four bytes in this case it that's like a hex address on its own trying to jump to that isn't going to give us the right thing see what i mean the way that this is put together is it is real legitimate bytes and those bytes as i mentioned to you well sure we noted them with 0x to prefix this is a hexadecimal but that's stored within memory in a super special way it takes the backslash x representation when we want to refer to these as real bytes but it also flips them in a weird way and that's called little endian encoding and it actually kind of takes and rearranges all of these uh and i'll show you that to you in a backwards way say we had this right here but we wanted to start from the end working at a bite at a time and have it flipped backwards saying that out loud i know makes no sense but what if i said this is going to be the same as f1 or sorry f6 grabbing this and then nine one grabbing this byte zero four that byte zero eight that byte whack right now obviously as a hexadecimal value that's wrong but denoting each of them as their own byte that is the way to properly represent that because little ending encoding takes okay the last couple bytes and flops flip-flops them let me show you that let's try and copy this in and bear in mind that backslash x is again just a kind of prefix formatter to tell something like python hey i want to represent this as a byte value i'll include that in as a string here pasting that in but we see we have some weird character here we could like copy and paste this and we could try and run this in the program itself but the backslash x's are still going to be interpreted as if they were literally a backslash x and not how we want the bytes to be represented so we kind of have to rely on python to actually print this out for us i'll use python tax c how about that so i could actually use like a command all within one line without ever actually opening up the python interpreter itself it just executed it and brought me back to my regular bash prompt so let's actually go ahead and actually use our python3 but we'll have to do something weird and wacky because if i wanted to print out all these values does it keep these here are those actually displayed i'm not quite sure let's try and pass that to xxd so we could see the hexadecimal representation of it and i do see it here you'll notice our our 910408 we also had a c2 in here though so was was there some oddity um that byte might have been represented like a unicode character or something strange so maybe it's probably best to represent that as still how we saw our backslash x to begin with that was what f6 yeah let's print that out to the screen so that will display it but reading the bytes with xxd having that just displayed out in its hexadecimal output is it doing anything weird there i'm not quite sure you know what let's try and kick it over to the program i'll use pipe to dot slash vuln that still breaks because our bytes are wrong [Music] so let me tell you our print function isn't exactly our friend anymore because it's trying to play nicely with those things that could be represented in another way like maybe potential unicode bytes stuff like that they have a different sort of character setting coding voodoo magic witchcraft that we don't need to really dive in the weeds on but we know that we can't trust our print function anymore so let me tell you in python 2 that used to be just fine but in python 3 we have to do some other boilerplate stuff if we want to do this all in line we would use something like the sis module and let me add a semicolon to denote hey we'll use a new command here and i'll actually use something really weird i'll say cis dot standard out dot buffer dot right and that is the function that we'll call to try and display this here um let's see how does that come through no python 3 needs everything in bytes right if i didn't want to print real bytes so we'll have to prefix that with the character b right in front of the string that's how we can tell python 3. this is a byte string and that'll naturally and properly interpret our backslash x representations so we'll fire that up and ooh now we have some new output and piping that to xxd to get that hex output now this looks like exactly what we wanted f6 f6910408 which is what that value from read elf was while it was originally given to us in hex we want to represent it in that little endian format yeah you following i know there are a lot of steps here and maybe i'm not doing the best job of cutting through it but i hope you are following just a bit if i had this output running and if i kick that to our vuln program ooh you see that we jumped to the correct address and this is the output that we would have expected from within the win function defined right here there's that printf output so we did it we jumped successfully to that win function now we just need to have our own like flag.text let me go ahead and echo something hey we'll put like a john flag please subscribe and wrap that into a flag.text now let's run the same payload that we had previously using python to display these bytes and pass it to the program and there it goes it displays that flag for us so that's it that's all we needed we needed to go ahead and carve this out and actually send this to the remote service which we have here and oh we only have 35 seconds left so let's do it super duper quick i'll copy and paste this code let's get the same command we were gonna run but rather than to our local binary pass it to the remote service please enter your string oh it's not going through it it's not actually sending it what are we doing wrong here do we need to echo this out or something pass it through with parentheses uh something was super duper wrong in that setup well echo was probably going to end up displaying all that so can we echo super quick no that's not figuring it out dang we ran out of time so let's take this one step further i'll restart the instance and rather than trying to do this through hey just one crammed command line let's write a python script to be able to actually exploit this thing and send it in a natural way you want to do it let's dive in i'll go ahead and restart the instance so we have a little bit more time that'll probably give me a new uh actual hostname or port or a different port number one way or the other but we've sort of made sense of how this whole structure came to be right what if we were to write a script called exploit dot pi and i'll add a shebang line of course it is going to be a python script but i'm going to import a different module on import socket which is the built-in python library for allowing us to interact with like a remote socket or port out somewhere out on the interwebs i'm actually going to go ahead and import arg parse yeah so that way we could tell it hey what host name report we want to use for a given command line argument if folks aren't familiar with the syntax of arg parts that's totally okay let's try and crank it out together let's say we have a parser object or a variable that will end up retrieving the command line arguments that we want to have our program understand we'll create an arg parse argument parser object there we go and now our parser will take a little bit of know-how it's going to want to have arguments added to it with an add argument function we'll take in a host argument yeah and we'll supply some keyword arguments that might represent how this is going to be interpreted look it's going to be a type of a string because we know hey a host will just be like an ip address or a domain name and we can say help or like the description can be the host name or ip address to connect to and i'll add a comma there so that python black will clean that nice and easy for me and we'll do the very very same we'll actually add another argument for the port that of course will be an integer right just a number representation and we could say the port for the service to connect to and then once we're done with that we'll have to go ahead and say args will equal our parser parse args and all the variables that we might want to refer to are represented within our args variable uh let me show you that let's do it hey print args dot host or and actually args.port cool does that make sense we're just going to simply parse the args and then put them out on the screen so let's run our exploit script and we did not supply the proper argument so it said hey hey hey hey we actually need these they're required so if i were to add in what is it uh saturnpicoctf.net at four 609.40 paste that in six zero nine four zero there we go now just printed these out nice and easy for us but we wanna use our socket to connect to it right so let's use a context manager kind of the same way we've been doing with like file handles but actually a remote socket handle and we'll use the constructor for a socket object within the library or module that we're using and we'll just call that with the as keyword something like the connection right that will automatically close the socket for us so we don't have to run a connection.close at the very very end it just handles that all for us now we could do uh actually receiving data or sending data to this socket let me show you that let me do connection dot recv that could work right we could be able to receive and send bytes back and forth but we need to like actually connect to the host and port first right so i know it sounds weird i'm creating this connection object but we have to actually make the connection with a connect function as a property of the socket object that'll take in a tuple so parentheses inside of the parentheses and we'll give it our args.host and args.port yeah okay let's see if that works i'm just going to run the script super quick no errors so that looks good to me and now we can go ahead and do like oh the connection dot receive that i was referring to i'll print that out so it's displayed here for us but receive is an oddball in the socket uh library it actually takes one argument as to the maximum number of bytes to receive it's kind of a standard boilerplate thing just to pass in 4096 as the argument for receive so running that after i save the script it gives me the byte string hey please enter your string and the newline character ready to receive data we could decode that if we really really wanted to and that'll actually go ahead and remove the byte string quote surrounding it but that's nice and dandy we want to be able to actually add our payload and and send that connection.send given a payload variable we'll create so let's actually build this payload let's say we had um let's keep it weird let's make it an empty list for this sort of thing yeah actually let's define some things that could be present in that inside there we knew that we sent a lot of a's yeah we actually sent what was it 40. let's go back to our notes here yeah we sent 32 plus 6 which was um 36 30 did i say 36 32 plus 4 which is 36 and then add 40 and then add 44 actually okay and then we had our new instruction pointer value so let's go ahead and say 44. and actually let's keep track of that because that's actually valuable information let's say that's an offset to where our instruction pointer might follow we'll have a new instruction pointer i'm adding an e in here to refer to the register name extended instruction pointer it's not super important but we knew that our new eip was this previous value f6910408 as the little endian representation of the wind function that we retrieved from read elf now we carve that out manually just kind of flopping the bytes around but if you really really wanted to you could actually use some other kind of magic within python and create a little endian representation based off the original hex value that you got from read off so you don't need to worry about figuring out oh the backslash x reversing things around i'll show you what that is you're using the struct module in python and that module will let you actually pack data and represent bytes in some way or another you'll have to specify how you want it formatted and this is kind of a special thing where you have to press the i believe button it takes a specific format specifier being oh less than symbol means little endian and capital i means integer or i think right we could at that point pass in 8 0 4 0 9 1 f 2 or whatever the heck this was that's the benefit of hey us using redelf tack elsevon grabbing the win value right here that we saw previously and denoting it as hexadecimal in python let me try and print this out super quick and i'll actually uh have that displayed we'll run that there is our byte string i know this is going to error for the moment but we know okay we are properly getting the new instruction pointer or the new location that we want to go to in the binary so we'll call this new eip and we'll bring that down to where we had it previously nice and easy the thing is our payload right now is a list um we want it to be a byte string so let's actually bring it all together with the same way we used to join stuff previously but let's add a b prefix so it can be bytes we could do that with our payload and in all honesty we could probably make that cleaner by doing this join statement like as if we were doing it for the declaration of our payload right here i know it looks kind of messy and that hey we got a little bit more indentation going on now but that sets us up so that we have a nice structured understanding of how our payload works and maybe anything that could follow it but ultimately we are just overflowing to the point where a's crash through the buffer clobber the return address and we give it a new instruction pointer to jump to which is the value of that win function within the volume binary now when i send this it's just gonna send it but we didn't see any other data because we didn't receive anything else our socket sent it and then closed based off of our contacts manager so let's try to now go ahead and receive anything that follows after we sent our payload and let's see if it'll just spit it out for us not seemingly okay what have i got going wrong here is it gonna get an error somewhere part of me genuinely doesn't know i'm not i'm not quite positive what i'm getting caught up on right now i am sending our payload with the right instructions do i have to add a new line character at the very very end here that might make sense we are of course hitting enter after we send it so let's add and tack on a backslash n bytes to represent a new line that's sure nice and easy to say we hit enter on our keyboard with a netcat connection let's try and see what this gives us ooh okay time to return fingers crossed we are jumping to the address that we expected let's see if the next line that follows is the flag and it is addresses are easy that is the flag and we could actually not print out that line before it so we have a nice and easy get flag script that is our exploit ladies and gentlemen and we have completed our first buffer overflow for pico ctf 2022 sweet we spent what 40 minutes on that thing hey i hope you had some fun i hope you learned something new look at that we have plenty of time left after we scripted it let's go ahead and paste in this flag and that challenge is complete 200 done uh challenge that has less than a thousand solves but we cruise right through it and learn some good stuff all along the way i hope that all made sense i hope hey building it out from the command line first kind of getting the high level theory and lecture on what the stack frame looks like finagling and bumping around trying to find a proper offset based off of what we knew the buffer length was and then really putting it together in a smart way in a python script this gives us a lot of flexibility for other opportunities in the future for buffer overflow or binary exploitation stuff like this and i know we are going to see some other buffer overflow challenges for pico ctf 2022 so this is code we might have to uh hold on to maybe keep for our own notes but uh with all that said everybody i have been rambling for way too long and i hope you did enjoy this video i hope you learned something new and if you haven't maybe hey go explore some of the other buffer overflow videos that i've done i have way too many on my channel but i know it's an interesting and fascinating thing that people are interested in and it does help it helps you learn that grit that tenacity that stubbornness and determination to get this thing right and capture that flag thanks so much for watching everybody i hope you enjoyed this video if you did please do all those youtube algorithm things like comment subscribe anything to help the channel grow share support i love it thank you thank you thank you everybody i'll see you in the next video take care
Info
Channel: John Hammond
Views: 41,186
Rating: undefined out of 5
Keywords: cybersecurity, learn, programming, coding, capture the flag, ctf, malware, analysis, dark web, how to learn cybersecurity, beginners
Id: k4hqdVo3cqk
Channel Id: undefined
Length: 44min 26sec (2666 seconds)
Published: Wed Apr 27 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.