Angstrom CTF 2021 - Pwn Challenge Walkthroughs

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in this video we're going to take a look at some of the phone challenges from the recent angstrom 2021 ctf any scripts that work on throughout this video will be uploaded to github so you can check the description for the link to that and you can use the chapters feature if you want to skip to any particular challenge but i hope you enjoy the video if you do drop a like and subscribe thanks the first binary exploitation challenge is called secure login and the description here tells us that we have a really secure login service we're given a link to the binary and to the source code as well so we want to have a look at the source code try and identify the vulnerability we'll test it out locally against this binary and then once we've got it all working we'll go to the actual binary on the shell server and try and get our flag so i've already logged into the shell server and i have downloaded the files so let's go and take a look at the source code before we jump into the source code let's do some basic file checks as well so we can run file on the login binary and see there's a 64-bit lsb executable it's not stripped so if we didn't have access to source code this would make it a little bit easier to reverse engineer and debug it because the symbols won't have been stripped we can also run checksec as well to get an idea what protections have been enabled and this can give us a good idea what the challenge is going to be about as well so in this case we have stack canaries so there's a good chance it's not going to be a buffer overflow if it is a buffer overflow then nx is also enabled so we wouldn't be able to execute any code that we're able to inject onto the stack and there's no pi so the each time the binary loads it'll have the same address we wouldn't need to leak that so there's no point in playing around with the binary we might as well just go ahead and open up the source code first of all see what's actually going on with it so if we step through the code we have a message saying welcome to the ultra secure login service and then the generate password function is called we have a note here as well no way they can guess my password if it's random so generate password is going to open the dev u random and it's going to read in 128 bytes into the password char buffer and it's going to close the file next we have an input which is also 128 bytes and we're asked to provide a password again it'll take 128 bytes there's no overflows or anything there and then it's going to compare it's going to use string compare to compare the input that we've provided against the password which is read from dev you random so in order for us to for this condition to be true and for its reading the flag we would need to make sure that the 128 bytes that we enter matches the 128 random bytes from dev uranum which will obviously be random each time the program loads so we could minimize this and run ltrace with login we'll see here it's open dev you random you can see it's grabbed 128 random bytes and then it's asking us to enter a password to say hello and it's compared the hello that we've entered with the 128 random bytes and therefore has said that's wrong so i've created a fake flag here flag.txt just so that whenever we actually meet this condition we'll be able to well we would still know anyway because we'd get the error saying missing flag.txt but i'll just put that there anyway to so that it'll print it whenever we do whenever we do match condition so what's what's the vulnerability here well debut random is going to bring back 128 random bytes so each one of the bytes it returns is going to be a possible value between 0 and 255 so it's 256 possibilities and one of those could be the null by so backslash x00 which we also know as as a string terminator so whenever the string compare occurs if it reaches a null byte then it's going to terminate that string and essentially it'll be comparing everything up to the null byte with our password so there's essentially a one in 256 chance of the first the first byte that dev you random retrieves being a null byte and if it is then it will compare the null byte to our input so if we can just input null by that will essentially bypass the other 127 random bytes that would be returned so we can essentially brute force this right so if we run if we keep running the program there's a one in 256 chance that we're actually going to get the flag so we can run it say a thousand times and the chances are we'll get our flag so let's let's test this out then so i've i've already got a script here which i just copied over the phone tools template which i normally use on these videos and i also call it exploit.py let's open this up and take a look so a lot of this is just um kind of functions that are in the template we don't need to worry about it the only thing that we've actually added in is everything after the exploit goes here section so we provide our exe in this case this is set to the remote server so let's set this to the local login um i've just disabled login to to make this a bit cleaner so essentially we're looping a thousand times here each time we're launching the program and we're hoping that whenever the program launches and it generates this password that the first byte that gets back from dev u random is a null byte if it is then the null byte that we enter is going to match that comparison right here and it's going to print our flag for us we've got a fake flag for testing locally so let's run python exploit and you'll see saying enter the password it's giving us our fake flag if we wanted to we could say io dot receive until and then receive up until the the password bit so if we do that again now it just gives us our fake flag and notice that on the first run we got it back twice and on the second one we got it about six times so uh because it's random obviously there's a one in 256 chance of it coming back as a null byte and that's uh that accounts that variation so now that we have that working locally we can go and test it out on the remote server so we go over to the remote server where i'm already in the correct directory here so we were told that this is where we needed to go to test this remotely and we've also copied over the python script so in our root directory we have secure login it's exactly the same as the script that we were just testing locally apart from the fact that the exe location has been updated so we can now run python and give it that file location it might take a little bit longer to retrieve the flag on the server okay it didn't take too long and you can see that we've been getting art we're getting our flag back there as well so that has been the secure login challenge let's go and check out some of the others our second challenge is called tranquil and we don't have too much information here in terms of description it says finally inner peace master oogway and we have a link to the binary to the c source file and then the server that we want to connect to once we get it working locally so i've already downloaded all these files let's go over to our local directory see what we have so we've got our source file but before we have a look at the code let's do some basic file checks we can check the file type of tranquil and see that it's a 64-bit lsb executable as as with the previous challenge it's not stripped but we have access to the source code so that's not really too important let's run checkset as well and we'll see that there are no stack canaries this time so that's a hint that we're probably going to need to overflow the buffer however nx is enabled so it's unlikely that our goal will be to try and get some shell code executed so it's more likely we'll be looking at some rock gadgets or maybe a simple return to win style challenge we could run the program let's let's run tranquil and we'll see it asks us for a secret word we enter in a word we get login failed we could try that a few times and give some longer inputs to see if we can actually get a segmentation fault in fact let me do that now you'll see we've got a segmentation fault so there's a buffer overflow there let's go and try and find out where it is let's actually first of all as well let's run ltrace on that and see so it asks for a secret where it's calling gets let's see abc and we actually see that it's doing string compare with password one two three so if we run that again and enter password one two three we get logged in the flag is somewhere the flag is somewhere else though so we are we were able to actually get the password there but let's go and have a look at the source code and see where the buffer overflow is so we'll open up tranquil.c and here we have our main method we can see it calls vuln and there's another function here which is actually commented out called win and we can see this function up here which prints the flag so if we have a look at the volume function it declares a char buffer 64 characters and it asks us to enter a secret word which is going to be retrieved into this char buffer but notice that it uses the insecure gets call so rather than using fgets which allows you to specify how many bytes you'd like to read in this is just going to allow us to define how many bytes we want to write so if we were to go and have a look at the the manual forgets we see that it says right here never use this function and we can go and have a look at the bugs below where it says never use gets because it's impossible to tell without knowing the data advance how many characters gets will read and because gets will continue to store characters past the end of the buffer is extremely dangerous to use it has been used to break computer security use f gets instead and um you can go and have a look at this to get more information about it so we can see that there's a vulnerability there and we know that we're gonna need to write more than 64 bytes then before we're going to overflow the buffer and overwrite the return address and essentially what happens here is whenever volume is called the the address that's going to return to you gets pushed onto the stack and whenever we get to this return down here it's going to return back to the function that called it which would be our main function so if we can overwrite the address that it intends to return to with an address of a different function for example this win function then we can get the flag in this case so this wind function it has no there's no path to execution right without a buffer overflow here there's no there's no way that a user can interact with the program and have this function be called so let's go and try and identify exactly what the offset is we could try and do this just manually fuzzing you know 64 characters and above to see how it goes but it'll be easier for us to do that in gdb so i'm going to open up gdb pwn debug and pass in the file tranquil in here we could have a look at the functions we could see that we've got our win function right here and that's where we're going to want to jump to we can generate a cyclic pattern then so we'll generate a sickly pattern of 100 at the end of the day we don't need to write too many bytes we know that we're going to need to overwrite 64 to get to our return address but there's no shell code or anything to inject onto the stack so all we really need is the um to identify where the buffer overflow is and then we'll need four bytes on top of that to write our address so we generate our cyclic pattern we take a copy of it we'll run the program and paste that in the program crashes as we would expect and we need to have a look at the beginning of the rsp here to see what what bytes we're in at what part of that cyclic pattern and to identify the offset we can do cyclic l and paste that in and see that it was 72 bytes in so we need to write 72 bytes before we'll be able to overwrite the return address you can see here it's going to return and we want to return to the address of the win function so we can actually just do here p win and that will give us the address right there as well so to help visualize this and make sure everything's set up correctly you might want to create a fake payload here so we can do python dash c and then print out in this case we'll do a x 72 which is going to be how many bytes we want to write before we'll be overwriting the return address and then we'll add on to that our b's so i'll say b times 6 and then we'll follow that by some c's which aren't needed in this case but that would in some cases be our shell code so i'll put say 30 c's after that and we can print that out copy this over and then just run the program again in gdb and paste that in and this just allows us to visualize this a bit better so we can see all of our a's leading up to our rsp and then we have our six b's from the beginning of the rsp so everything is looking good there and then everything else on the stack would be our c's but for us we also want to go to the win function so the win function let me take a copy of this if we go back to our python payload generation here what we could say is instead of doing b times six we can we can put in this value in hex so if we do plus backslash x we need to do this in reverse order so we'll do backslash x 96 backslash x one one backslash x four zero it's just because it's in little endian format so each but we're reversing the order of the bytes and if we print that we don't get a recognizable payload here so we need to print this to a file so i'm just going to pipe that to payload and then if we run this again if we run this and pipe in our payload you'll see that we've actually got our fake flag so in this directory i already have flag.txt which is just a fake flag that's set up and that worked for us okay so we can also try and run tranquil and just send in the payload and that also works we get a login failed but it is correctly jump into the fake flag we could go ahead as well and try to set up a breakpoint in this so if we wanted to let's um disassemble main we can see our main function here let's actually disassemble full and the volume function returns right here so we might want to set up a breakpoint on that function and then we might want to run it with the payload and you'll see it runs through it's actually stopped.breakpoint and you can see that instead of returning to where it should be returning it's going to be returning to this 401196 win function if we hit next we'll see yep that's exactly where it jumps to we can continue it and then we'll get our flag here as well so the way we just identified the correct offset and set this up we actually don't need to do any of that in gdb or elsewhere we can set up a pontool script to automate that process for us now i've already set up a point tool script to do this so let me just open it up exploit dot py and this is the same template that i normally use on these scripts so all of this stuff up here just stays the same from challenge to challenge i did slightly change this find instruction pointer function so the first thing that we do here we can just even comment all of this out the first thing we do is try and find out the offset we know the offset was 72 so we could just type in here 72 but um we can also use this function to find it so this will launch the process and it it'll wait until let's run the program again it'll wait until it sees this colon and once it sees a colon it'll send a cyclic pattern of 100 bytes it's then going to wait for the program to crash and then we're going to check the offset so you can see i've commented out the 60 the 32-bit code which would have read from the program counter which notice right here uh whenever we overflowed the buffer here where's the a's okay so whenever we overflow the buffers the a's don't make their way into the rip because they're not on about not a valid address but on the 32-bit system they would so we would read those the cyclic bytes from the program counter rather than from the stack pointer but in this case we read it from a stack pointer and let's try and run this and make sure it's working okay if we run python exploit you can see i have the debugging on so there's quite a lot of information there we don't need to worry about it too much but essentially it's showing us this is where the fault was and this is the values and hex and it's basically just searched in a cyclic pattern to find out where where whereabouts in the cyclic pattern were these bytes and it's found that they were 72. so with that done we've got our offset we can launch the program and here we want to say our payload is going to be 72 bytes of a cyclic pattern so we have our offset here and then at that offset we want to write the address of the win function so we could just go and let's go back here and do p win we could just take a copy of this and paste this in here that's absolutely fine as well but because we've actually loaded the executable file in here we can just read the functions that are available to us so i've chosen to go for that root instead we then write the payload to file so we can reuse it send it get sent to the server and stuff like that and then we just wait until we get that message to say the logins failed and then we take our flag so if you try and run that now let me clear this python exploit you'll see it sends all that off it comes back and retrieves our flag for us and the cool thing about this template about this template that we use there is we can just pass in gdb or remote as an argument and we can set up our gdb break points and stuff here as well and that means we don't actually have to go and start changing the script depending on whether we want to debug it or whether we want to test it remotely so if i just go and grab this server and port number and then we run the exact same thing again python exploit but type in remote and then just paste in the server and report and hit enter and that does everything for us we get our flag time has gone too fast without watching the leaves fall from our instruction pointer and there's our flag we could have also used a rop object here as well to call this but i'm not bothering this in this case um okay and let's move on to the next challenge the next challenge is called sanity checks and as usual we have a program and the source code here as well it says on off chance that someone does get in i've added some sanity checks to detect if something fishy is going on see if you can hack me so we again want to test this out locally and then we'll be able to try it against the server so i've already got the files downloaded into our local directory so if you list the files in the directory we have a fake flag for testing we've got a source code we have the binary so we can check the file type and as usual it's a 64-bit lsb executable it's not stripped if we go and have a look with check second the file protections will see that there's no stat canary so again good chance will be a buffer overflow in this case but it doesn't look like we'll be trying to get any shell code on the stack to execute because the nx enabled flag is set and there is no pi so we could run the program again run checks asking for secret word we can just enter something in login failed okay so we could try that again with ltrace that's the secret word we could enter something in we can see that it's actually compared it with password one two three so if we run that again and this time we'll enter password one two three and it says logged in let's just do some quick checks to make sure everything's in order and it says nope something seems off something seems off so we could run that again just without l trace and you'll see that the output a little bit more clearly but let's go and have a look at the source code and see what's going on so we'll open up checks.c so we've only got one function here the main function so it's not like our return to win style challenge where we had to jump to another function in this case so we do still have the password of 64 bytes and it's it's reading that in with gets the dangerous function which was is not going to check to make sure this is going to fit within the within the buffer so we will be able to overflow the buffer we need to make sure as well that the password equals password one two three in order to pass this check and then we have some other checks to that need to pass as well so these variables declared here they don't really the naming doesn't seem to make much sense they're all set to zero and then after the password has been verified it will go through and check each one of these variables and make sure they equal certain decimal values which obviously they shouldn't equal because they've been assigned as zero at no point have we been given any option to change that there's no code anywhere here that's assigning them new values so unlike the previous challenges we've looked at in this case our goal is going to be to actually write over these variables with the the values that we need in here so we can play around with the offset and find that if we enter in our password and then enough bytes to overwrite this 64 byte buffer we'll start to actually eat into these variables which are on the stack and we can overwrite those with the values that we need so let's open up gdb gdb prone debug checks and there's only our main function here but we can check info functions to get a list and then in this case we want to disassemble the main function and there are some different instructions here we might want to set breakpoints at so we have our string compare where we compare the password so let's set up a breakpoint there and then we have our comparisons here as well with the different values so 32 in hex is 50. so that's our first check and then we have 55 is going to be compared to 37 and hex so we might want to set some break points up here as well let's just set up a break point at the first one once we get the first one working then we can set up break points of the others if we need to check the alignment let's do b star set that break point up and essentially will be as we're building up our exploit in our payload in pwn tools we'll be able to go and set a breakpoint here and find out what does rbp minus 4 actually equal and depending on what values in there based on what our payload is we'll be able to adjust our offset until it actually aligns so that if we inject this a value of 50 decimal we want to make sure that it's being injected into rbp minus 0x4 so we could run this let's generate a cyclic pattern as we usually do to identify the offset and but in this case obviously we're not looking to overwrite the return address but if we run that and paste that in we hit our breakpoint but obviously this is the comparison of the password so if we hit continue it's going to fail to log in because we didn't have password one two three in there so that's fine we just need to whenever we run it we'll need to put in password one two three before we put in our cyclic pattern and we'll need to account for that then in our with our cyclic pattern as well so now if we go to search for whatever's made it into the rsp let's hit continue we have aaa y so we can do cyclic dash l and that was 93 bytes into our pattern but obviously then we also had our password one two three as well so that needs to be taken into consideration but i just wanted to just go and quickly demo that in prone tools uh sorry in gdb pondy bug we'll actually move over to our pawn tools script now so open up exploit.py this is i've already put this together so i'll just rather than go and type in all the code out on street on video i'll go through and explain what's going on okay so as usual we're using our prone tools template here it's set up to grab the context and we don't need to worry then about the architecture and uh how many bits and stuff to use for addresses throughout it'll it'll take care of that for us we have our find instruction pointer but in this case obviously that's not exactly the offset that we're looking for but we've set that up anyway and we send in the password one two three and our cyclic pattern as well and then we just adjust the offset based on the length of our password so that'll come back with the offset and then we want to send off our payload our payload is going to be the password again because we need to we need to match that first check in order to get into this con into these if statements and then we're going to put in our values so we have 0x11 there which is these are in reverse order here so we have a 32 or 37 or f5 [Music] and i kind of played around with this just with um in this case we're minus 16 from the offset in order to account for these and i just kind of played around with this value so you'll see i set up some breakpoints here the first one being i think this is actually our two comparisons there so let's let's try and run it with gdb if i go back and we also write the payload to a file here so if we do python exploit gdb let's move this window over here and it stops at his first break point so if we hit enter let me actually minimize the this you can see a little better and we stop off at this comparison so this is our first comparison we're comparing 32 in hex to whatever's in rbp minus four so in that case we would have a look and see what does rbp minus four actually equal in this case it does equal 32 because i've been through and checked this um i went through and made sure these were all in alignment so whenever this wasn't matching what i would do instead is print out x over 20 x and let's say minus 16 and then try and work out where is our value in this case you can see it's right here so you just go and add four bytes at a time until you get until you work out what the right offset is and then after that it's going to go on to the next check which is going to be 32 and that's going to be checking rbp minus 4 sorry minus 8 so you can see that's at 37 37 i mean not 32 and then similarly we'll do the same with our minus 12 is going to be f5 and then again 16 is going to be our 3d oops 3d and then finally 11 at 20 minus 20. so it'll go through all those checks if i hit continue here it's going to stop off for that next breakpoint as well i believe and you could just go and make sure everything's still in place i know in this case that it is going to be and it's if we just hit continue it'll print out our flag so i think that's i think that's basically everything that needs to be mentioned here now in order to test this on the remote server all we have to do is run the same script with the server address and port number so i can just take a copy of this and then we can run python exploit remote and just paste in the server address and the port number and that'll that'll get us offline and that's been the sanity checks challenge so let's move on to the next one the next challenge is called sticky stacks and again we have the program we have the source code and we have the service connect to and we're told that there's a lot of secrets maybe even a flag so we've already got the files downloaded here we can see that we've got the sticky stack so let's check the file type and again 64-bit lsb executable it's not stripped if we check those security settings we'll see that there are no stack canaries nx is enabled so if there is a buffer overflow we won't be able to execute any any code that we inject onto the stack pi is disabled once again so let's run the program see what it does so asks us for a name and then it just repeats that back to us you can see here it's not actually repeated the full thing back to us either there's only one opportunity for input and there's no buffer overflow here so let's go and have a look at the source code before we do anything else so we have the secrets struct which is declared here containing a variety of char buffers including the flag which is what we're interested in retrieving whenever the program launches it's just going to call vuln and vuln is going to set this seven by name variable which is what we saw whenever we put in crypto it only repeated crypt back and then it's going to create a secret struct object and assign some values to some of these items in it and it'll open up the flag.txt and it'll also assign it'll read in 128 bytes into the into the struct it's then gonna ask us for our name it's gonna read in six bytes so there's no issue with the buffer overflow there as we saw but it's then gonna print out welcome and then just print f the name that we provide so this is a clear format string vulnerability because the developer hasn't specified what type of input we're providing they should have specified that they're expecting to receive a string and therefore whatever we enter should be interpreted as a string because they haven't done that they've allowed us to do that for them so if we go back here and run the program and put in here percentage s there we've got welcome welcome let's do that again and we'll do percentage oops percentage s percentage s and we've got welcome null we could do that again see if we might not be able to fit three though okay so um and this is essentially reading items off the stack so we could do that again and try and represent this as hex again we can do percentage x percentage x but because we don't have much room to write here we can't keep looping through and going through all the items on the stack so we need to use a different notation to do that and to do that we can say here percentage and then give a number let's say element 13 and then dollars so we're saying we want to print out the 13th element on the stack and we want to represent it in this case i'll say as hexadecimal and then that'll return so we could do that again and we can do this if we're doing this with the string what's um what we need to be aware of as well you see we've got a segmentation fault there so when we try to print as a string we're not actually trying to print the item on the stack as a string we're trying to print the item which is pointed to as a string so if we have on the stack four a's for example that would be four one four one four one in hex and we would be trying to print whatever is at that memory location as a string which obviously is an invalid memory address so in a case like this we get the segmentation fault so in that sort of case we would actually want to print it as hex as we've done here and then we could simply take this and decode it on in python or cybershare for ascii to hex.com and find out what it actually equals in text so we're going to want to try and loop through the items on the stack print them out and see if we can start printing out some of this information and hopefully get to the flag so again we've got a local fake flag set up to test this out and i've already got our scripts prepared as well so let's open this up so i already have this set up with the correct values but initially to solve this i just looped through like one to a hundred and we're printing out we're printing these out as pointers we could print out as hex but it's not gonna give us this full 64-bit that we'll need so if we run this you'll see that it's actually going to crash because i'm trying to convert these all into hex and that's not going to work for us so first of all we'll just want to comment some of this out and just print this print out the result and then we can change this to warnings we're not getting so much noise and if we run through that we're printing out all the values and essentially we can go and try and look for something that looks like a string or we could go to ascii to hex.com so if we go and take let's do cut out the flag so we just got here our fake flag and if we were to go and convert this you can get an idea of the string that we're looking for so let's go back and we're looking for a six six six c which it looks like we're going to have around here bearing in mind the ordering may be different but um we can then take this let's take this actually and convert this back on ascii to hex and you can see there so we've got the flag but it's reversed we've got the first half of the flag so essentially this code here all we're doing is we're ex we're converting this into hex and then we're also reversing it as well and appending it to the flag which will be printed out at the end so whereabouts was the flag there it was that oh we're not printing out the number i believe it's around like 31 let's let's print 31 to 35 yep 31. so if we do 31 to 33 and try to convert it into hex you can see that it's got back our flag this time it didn't give us our success flag at the end of us because we've turned off the login so we've put that back to info run that again this time we'll get our fake flag at the end so then we just need to do the same thing against the server i i'm just gonna i'll revert this back to what we had because it was 33 to 43 because the flag is a lot longer but if we now just use the exact same script and we'll go and take the server and port and then we can run this again with remote paste that in and that's going to come back you can see it's getting each segment of the flag and then at the end it's going to reverse those all and append them together and then we get our flag and that's been the sticky stacks challenge so we might check out some more of these challenges i'm going to move on and have a look at some of the reverse engineering and web challenges as well
Info
Channel: CryptoCat
Views: 1,721
Rating: undefined out of 5
Keywords: secure login, tranquil, sanity checks, stickystacks, angstrom, ångstromCTF, angstrom ctf, ctf, capture the flag, pwn, binary, binary exploitation, pwntools, ghidra, gdb, pwndbg, gdb-pwndbg, buffer overflow, rop, ropper, ret2libc, ret2win, radare, r2, binexp, debugging, reverse engineering, hacking, exploit, cyberchef, kali, infosec, cybersecurity, hacker, learn, walkthrough, writeup, disassembly, assembly, python, readelf, rop objects, pen-testing, challenges, hackathon, return oriented programming, hax0r, 1337, checksec
Id: 2pqG6opzrug
Channel Id: undefined
Length: 36min 39sec (2199 seconds)
Published: Thu Apr 08 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.