Binary Exploitation Deep Dive: Return to LIBC (with Matt)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello everyone hey thanks for clicking on this video coming to check it out i am super excited to bring this to you i think this is a gold mine uh and i really hope that you feel the same this is a long form video if you couldn't tell uh you can see the time stamp there it's about we're over two hours i think but i think honestly this is just full of nuggets full of really good insights full of really good knowledge and uh learning so this is a video uh that i did with a good friend of mine matt matt e matt ernschwender sorry if i butch your last name buddy uh we uh i i went up and asked him i just said hey matt dude you are a guru you're a ninja when it comes to binary exploitation you're a wizard in reverse engineering and this sort of stuff and i'm not truthfully so i wanted to kind of capture his knowledge and insight when uh i said like look dude would you be cool with doing a couple videos with me on youtube uh so this is the first one if we do more maybe let me know if you guys like this sort of thing um would you be willing to do videos with me on youtube where you sort of walk me through doing binary exploitation challenges and telling me how you would approach it what you do and what scenarios etc etc because i think that would be super good for learning i said like let's take a look at some of the pico ctf challenges so we can start fundamental and maybe get into more advanced stuff but i think all of this will still be super helpful and super useful so this is footage of matt and i getting together hanging out and working on some binary exploitation challenge um i think this is awesome because it goes through reverse engineering in ghidra uh debugging in gdb with geff or jeff or however you want to say that uh plugin and extension uh troubleshooting trying to understand why our exploit doesn't work the first time fixing problems understanding problems and just going through extremely thoroughly the whole process so yes it's a fundamental thing um it's just setting the foundation but i hope if you are someone that's interested in this sort of thing i hope this will be a really good video with uh lots uh lots of stuff to learn from and maybe we can do more of this if you really really like it so with that said i know this was a long intro and it's going to be a long video so i'm sorry for yapping but let's get to it this is footage for me hanging out with matt i'm recording this intro in the future that's when i recorded that in the past so i my hair will be longer but i just happen to be wearing the same shirt that we recorded this thing in anyway let's get to it i'll see on the other side hello oh you're good how's it going oh um i realized kind of at the couple minutes in i didn't have matt's audio for like the first couple minutes so so hey stupid mistake uh i realize it happens all the time it was an accident thankfully we caught it before we got into the real reverse engineering and buyer exploitation writing code etc uh but we did miss some of our initial setup so i'll walk us through that here uh very first thing we do is we're gonna take a look at the challenge that we're gonna tackle uh we're going through pico ctf they're challenged from the 2021 competition called here's a lib c which should be a return to libsy kind of attack that we would typically do in like binary exploitation and that sort of trend next we got started kind of preparing some tools and utilities that we knew would help with us in this process for solving the challenge uh we know we're going to be using gdb or the gnu debugger to debug and kind of step through the code as it works through our exploit and matt tends to use jeff or gef for gdb enhanced features as a plug-in or kind of extension you could use with the gnu debugger to aid in exploit development so he wanted to get me kind of spun up with jeff so i went to go check out the documentation online and i tried to install it originally they offer some kind of quick install script that you could w get down and then pipe into sh that didn't exactly work all that well for me and i don't always like to just w get content and spin it right into bash or sh that's typically a bad idea uh so anyway i just get cloned the official repository and i figured okay we can install this kind of manually with the pip install the requirements.txt file and get it spun up then all that we needed to really do was add in a source command into our gdb init file that would kind of initialize as gdb starts up so it could make sure to run that jeff script then i just wanted to verify i had all the tools that we might need we have ghidra we have pwn tools you can see i just kind of sanity check them there and uh i mentioned to matt that typically i tend to use peda or peda or the python exploit development assistance extension for gdb now matt told me hey jeff might be a better working one you could use some really cool stuff like telescope so i thought hey if i'm all i'm all here to learn so i wanted to give that a try then we started to download the files that the pico ctf challenge would offer us for this here's a libsy task it would offer the binary file that i would go ahead and just w get down as well as the libc or libsy.so.6 now because this is going to be giving us a lib c with the binary we know that hey maybe we're going to end up doing some return to lib c attacks uh i grabbed the make file just as well in case there's any strange kind of command line flags or arguments that are passed when that binary is compiled and then i just kind of spit together a stupid easy connect sh script so i can keep track of the netcat host name and the port number then matt kind of drives me down the road here where uh we would normally start to work with these files we will have a vol script or excuse me the vulnerable program and the lib c that we could use but when i try and execute the vuln or this program in binary it ends up spitting out a segmentation fault so there is a new problem that we kind of have to work through and matt walks me through this matt explains that the problem is that this binary or the vuln program that we would kind of check out with ldd to see the imports or what libraries it might load in it will work with libsy given in the current directory that we just downloaded but it needs to be linked in a specific way with kind of the matching version now it's going to use the linker that i have installed on my computer not what would have been used on the challenge server or wherever this can this binary was originally compiled so we need to know the version of the libsy and match it so that we could link it properly we could kind of figure out the version in a couple different ways we could try and just run the lib c as if it were a binary and it would give us hey maybe the strings are the version number that would expect that didn't work in our case so we could simply try and run strings on the lib c we could grep for gcc or a version number and we can see there that okay this is expecting a 2.27 version now we would want to grab the appropriate linker that would match that i'm running on ubuntu 2004 so if i were to take a look at my own linker that would expect to match my own libc version there it is on my machine in lib64 i could check out the version yet again but if i were to see the strings of my own we can tell okay maybe that's expecting 2.32 which does not match 2.27 so maybe we could run a couple different docker containers with older versions of ubuntu to see if any of them match that specific libc version i could go check out the directory for linkers and what they would expect and we could track this down grep for the version but oh we'll see 2.29 and then we could try a later version of ubuntu maybe 1804 or going back to 1604 etc etc that is a tedious process like it could work but we're kind of just playing whack-a-mole with guess and check so matt suggests a better option which is to use this tool and utility pwn in it and this is handy for setting up a binary exploitation challenge it will start to build out a challenge script for you it will help determine what libc or linker version that you might need so i go ahead and again git clone this process i try and run it from the directory that it started in and then it spits out a solve.pi script when i'm not actually working on a challenge so really you should run that within the directory that you're already working with the binaries in then it will go ahead and create a solve.pi script and it might determine okay you need this specific linker ld 2.27.so you can see it there now if i were to run the vulnerable program with that linker the program would run just fine that's perfect that's great that's what we want problem is if i were to try and run that dot vol program on its own without specifying that linker it wouldn't work still so we could use utility patch elf and this is another one that matt recommended where you can kind of modify the binary and tell it hey strictly use this linker that we've supplied that we were able to retrieve from pwn in it so that is kind of the dynamic duo they're using pwn in it to track down that link or libc version as you need it and then use patch elf to go ahead and get that set up with the binary all right we're finally done with all that prep and setup i'm super sorry for that like weird commentary through the speed run of getting tools and everything ready uh that was my bad i don't know why we weren't capturing matt's audio but we fixed it we found the problem before it got too late before we got into the whole process of kind of reverse engineering and writing the binder exploitation script etc so uh now finally we 10 minutes into this video i can let you loose on the real raw footage with matt uh i'm gonna let matt take it away he really just drives the ship here it's fantastic and i think there are a lot of great lessons learned so i'll let him take it away and i'll see you on the other side okay now that we've got um that binary set up i think we can go ahead and get started right yep sure the hard part's done awesome so i have an echo server seemingly yep so if you just try typing stuff you know your basic echo server great yeah okay all right so the first thing we should do is we should check what the protections are of the binary typically whenever you get you know a binary you want to check hey is this a dynamically linked executable is a statically linked executable is it a 64-bit 32-bit so you can check the um protections by using checkset it should be included with phone tools yep so just check sec and then the binary okay so we can see we have partial railroad which means the global offensive table is read and writable um there's no stat cannery so their worst was some buffalo buffer overflow in the binary we don't have to worry about leaking the cannery nx is enabled which means that any segment of memory which is writable is not executable so you can't just write shell code and then jump to it you have to get a little bit more creative there's also no pi which means that aslr won't affect the binary so every time the binary is run the actual base address is going to be at that hex 40 0 000. it's always going to be there because pi is disabled and then run path is just to say hey for looking for libraries look for the current directory that's how it gets that's how it runs your lipsy cool we figured out protections we figured out like kind of what it's doing just by running it let's try opening it up in general okay all right keidra gidra there we go success and we're on the latest version now so it's all success that worked out in the end you got your tips all right we're gonna have to make a new project so i will hide this i guess actually you might need to make a uh directory in your home folder so now it is the hotkey i to open a binary yep uh so i'm going into pico i'm going back to here's the loop c and opening up our volume okay okay just saying it's the l format and everything else more import results we already went through a lot of those import results just going through file and check sec awesome we gotta analyze let's find all the uh details do you do any magic do you click on any extras of those or no the default analysis is good enough i mean there's nothing really special you're gonna need all right so now we go into functions yep go find main so here's the main function um you can see in the uh thing compilation it just has a bunch of stack variables that's where the undefined eight is undefined for eight and all that yep so allocates a lot of memory on the stack so there's a lot of local variables um and then it does some weird just assign some of those variables i'm assuming just looking at this that the actual assembly code for the binary is is structured in a weird way so that the compiler engager can't really understand it so this is just the decompiler trying to interpret it but obviously it's not going to be doing well because the the actual assembly code itself isn't is kind of weird so anyway the first thing we have is as important as we have set buff so what this will do is we have set buff standard out and then zero or null what this will do in short is just make it so that the binary will behave whenever we're um connected to with netcat so there's it'll just like it works on your machine it will work on your machine if you didn't have set buff but if you try to netcat to it it would just kind of be a little bit finicky then we have just get e group id get a set regid so this will just get your group id and then set your set your um real effective in um group id um this isn't really needed for us because uh we're not we're not running a set uid binary which is obviously looks like stuff for set uid then we're setting some more local variables doesn't look too important just for some if it is important we'll go back to it but for now um as you can see going through the function there's no uh user input which if you saw like there's no scanf or f gets or whatever there's no user input and as you saw with our whenever we're running it it just printed something out and expected user input so as you can see you know we have that puts which means hey that's probably our that's just just guessing that's probably our printout with the welcome to the server just right now we're just you know going over guessing and then convert case is probably you know converting the case of the string just based on you know what we're seeing and then it actually goes into do stuff with the while true so let's go into that function see what's in there double click on it here yep so now we have some variables um then here's our actual scanf so scanf is a function which is used to receive formatted input so the format is the actual first argument for scanf so if scanf the first argument was percent d that would mean hey the uh program is expecting you know to imprint a number or if it was percent x it would say you know the program is expecting you to input a hexadecimal number and you can uh google all of these different um all of these different format specifiers for scanf to see like hey what type of input we can input but for this format specifier which is percent square brace that sort of like regex thing means we want to receive input up until the user enters a new line but don't include the new line just receive the input up until the new line so that's what that scanf will do then we have the other scanf which has a little ampersand dat whatever so if we double click on that see what the actual is and if you see in the actual listing view we have percent c now it's going to be kind of tedious to always go click on that dot that ampersand dat to try to figure out what format specifier is but to fix it what we can do is we know that is a percent c which is a string or a character array because there's no strings in c there's only character arrays so let's try to change the actual type of the variable so if we do retype global after you right click and we put char or you can go through the type yeah it's easier to type it just do char square brace and then put a two because we know it's two characters and then press enter we can see it starts to clean it up nice which is what we want then then what i will do is i'll store it in the local underscore 89 so what the reason we have two scanfs is because the first scanf will and we'll input we'll get the string from the user up until the new line but we still have a new line that was pressed that's where the percent c will take that new line then and store it in that variable i'm checking to see if there's any way i can make uh the display a little bit bigger oh yeah um should be in edits tool options and then just search for like font or something in the filter yeah sorry did not mean to derail you that's fine that's gonna be a bit big perfect so there yeah so we have our skin first scanf which gets the scree string up until a new line then the second scanf will actually get the new line which is you know whenever you press the enter key then after we do that we set a local underscore 10 to zero and then we we treat that as sort of like a iterator so we'll go so yeah you can call it iterator um and then else and then we jump to that while loop and while it's less than 100 we're going to go to that convert case right yep it just calls the convert case and then it treats that as an index into whatever string we enter so i'm assuming what this is doing is obviously taking your string and converting the case right and so we don't really have to like go into what the actual convert case function is doing because there's nothing like unknown going on then after that we have a puts and we print out your string after it was convert case and then we have a return then if we go back to the main which is where the return is i have to back a little bit more yeah i think i was jumping around everywhere just click on my it's just gonna keep doing that do well loop so we're just gonna infinitely just keep calling that d stuff function take input and as you saw when we were running the binary this matches what we expect yep now before we get to the actual vulnerability another bug in here is that um the variable that your string is that doesn't get meant set to null bytes so whenever you just uh go into the program run it enter a string and then just keep pressing enter it will always use the same string which i thought is pretty funny oh so that's that you probably saw that before but let me just a small little a good little easter egg yeah yeah but as you can see like with languages like c you can easily make that mistake where you don't set that buffer to null bytes again yeah you can easily see you don't set the buffer to null bytes but there's nothing warning you that it's being set to null bytes so you're going to see how c is kind of that language where you have to manually do everything and if you don't if you miss one thing it can lead to some issues and as you saw that issue was oh it doesn't clear out those buffers gonna keep printing it so anyway and the actual vulnerability for this we saw it would it would read in a string okay but it will only read in until it reaches a new line there's no count for the scanf it's just reason until there's a new line so if we just enter in like a thousand characters then you know the buffer you can see right there only holds 112. so we just yeah the classic spin it with a's i think that's plenty oh yeah as you can see we have the segmentation fault core dumps which is great whenever you're doing minor exploitation it's not great whenever you have a project um so we gotta crash which is great now let's try to go inspect the crash so what we can do is we can just run the program with gdb gdb is you know the program for debugging and then let's just run it so just do r run now enter in your input which is about tons of a's all right you might need to zoom out here a little bit so it crashed at this return instruction you can see at the bottom how it has that do stuff plus 156 you can see the current instruction that's being executed okay now whatever return instruction will do is it will take whatever value is at the stack since it's um system 64-bit it's going to get a 64-bit value or 8-byte value so it's going to get whatever is at the stack not whatever is in the instruction pointer so this is what i notice a lot of common misconceptions when going from like 32-bit to 64-bit whenever you're doing a buffer overflow on 64-bit and it gets to that return instruction it's going to check to see hey is this value on the stack point to actual memory and if it doesn't it's just not going to execute the return instruction so that's why you don't see your a's in the rip because gotcha because all those a's don't actually point to a valid address in memory so what you really want to look to is look at what your stack is so if you just do examine forward slash or x forward slash g for eight bytes x for a hexadecimal space and dollar sign rsp which is the pointer to our um stack let me print that out what will happen at that red instruction is it will put that value the ox414141 in the rip but since ox41414141 doesn't point to a valid area in memory it's not going to execute that return destruction sweet so now what we have to figure out is we know we uh overflowed it we know we have control of a value on the stack that will eventually be put into the instruction pointer let's try to figure out how many bytes it will take until we actually get to that instruction pointer so luckily with jeff jeff comes with tools installed to automatically do this if you type in pattern that's all pattern cool okay so here's the syntax of it you can do pattern create or pattern offset so if you worked with like you know metasploits um pattern creator pattern offset it's very similar to that so if you just do pattern create and then you can specify like how many bytes of input so let's try to figure out how many bytes of input we want to put in so let's go back to the uh this is the gedro so we can see looking at our stack variables the actual allocated buffer is 112 bytes but even if we overflow the 112 bytes we don't know if it's going to overflow past the instruction pointer because the way your stack's laid out you have your local variables then under that you have your saved rbp you have a cantering if there's a cannery then you have your instruction pointer so there's more values after your allocated buffer that you also have to overflow through the instruction pointer so what i typically do is just round the next um multiple of 100 so in this instance since our allocated buffer is 112 let's just try 200. so let's just do pad and create 200. and then it generates that string and what this string is should probably explain what it is so this is called a um it's it's really called a de bruyne sequence and what a de bruyne singlets means is that any subset of a set is only going to occur once or in this instance um what happens is we have a string of 200 bytes now if we try to find any uh four by or eight bytes in that string those eight bytes are only going to occur once it doesn't matter where you are you could be at the 17th fight get the 17th 1819 those eight bytes see um take those eight bytes compare it to your string and it's only going to be at that 17th spot so that's kind of how like a drawing sequence works um pencils it's called cyclic or cyclic pattern yeah it's probably more common because now a lot of people like saying de bruyne sequence but in mathematical terms it's a de bruyne sequence so now we saved it and then we can run it from the program again paste it in yep classic you know buffer overflow we reach the return instruction which is what we want we can see our stack is just overflowing with our input so now as you can see at rsp it's pointing to the um our string now with jeff what we can do is we can just use our pattern command again just do pattern offset is it pattern offset or pattern search oh i guess they kind of do the same yeah pattern offset cool now just do dollar sign rsp that's it oh okay that's awesome as you can see jeff just you know pretty much automates the whole thing that's also taking it searching it manually just does everything for you so as you can see it found two values one for little mdn and one for big endian since you know x86 machine they're little endian we're gonna get that value so we found that 136 is where our is how much input we have to put in until we overflow the instruction pointer just for a sanity check we should probably do pattern create that 136 and then tack on a bunch of a's on it just to make sure hey this is actually overflowing right so if we run it and then put a bunch of like capital a's or capital b's or whatever i mean you you should just put eight see if it's yeah but i have confidence in jeff that it found the correct offset i do too as it is so that's great we know our we know we have to input 136 bytes until we actually overflow the instruction pointer so now that we have that let's start actually starting to script this because obviously you know running it in gdb is going to get a little tedious so let's start our little poncho script [Music] start with that that she bang then we're going to do from phone import star i'm generally you should do just import phone yeah professional like python project you should you should never just do from library import everything just but since it's just you know a basic phone tool script we're just doing you know ctf stuff it's fine it's a ctf you don't care about quality you just yep you just want to get it done all right so in order to interact with the uh binary what we can do is we can use a function in poem tools called process so we just do process and then the path to the binary as the argument and then what that returns is it returns an object that we can use to interact with the process so yeah p works perfectly fine you can use i o you can use s whatever you want so then after we do that let's yeah you can do p dot close at the end it's generally uh what you can do instead of p dot close is if you do p dot interactive after um what this will do is this will drop you into an interactive shell where you can interact with the binary on keyboard you don't you don't have to programmatically interact with it because what we're trying to do right now we're trying to programmatically interact with it so that it makes you know writing our exploit easier but since we do peta interactive after our exploit runs we want to say hey like what actually happened can we just like interact with it play around with it so the first thing we know is we know our the amount of bytes we have to input until we reach the instruction point is 136. so it'd be a good idea to like make a string of 136 keep like a global that's 136 just whatever to keep track of it and then yep we can uh enter in our junk which is our a's times that 136. great so now once we have our input where do we jump to right because we can't execute off the stack yeah and there's also no win function you see with the normal like return to win so this is where the whole reason why they gave us the lip c so lip c is if you're unfamiliar with c what lip c is is a lot of helper functions that will allow you to just do various stuff on your system so if you've ever written any c program and use printf what's actually happening is you don't make the actual printout function you're saying hey this function exists somewhere else and that somewhere else is in lib c so whenever we do call printf we want program execution to go into lib c now along with in lib c along with printf there's a bunch of other functions there's a scanf as you saw with how we received input there's puts which is how we displayed stuff there's set buff which is what you saw in the binary but there's also a function called system and if you just look at the man page or system what it does is is that call three yeah c is three for like c functions yep execute a shell command so it's just system and then the string of what command you want to execute obviously we want to get a shell on the system so we're going to use the command forward slash bin forward slash sh you could use like cat space flag.txt if you wanted to but just to make it easy we want a shell so we're going to do forward slash bin forward slash sh so now system's a a function that exists in lip c and when the program runs it's going to load lib c into memory with the program so system does exist inside memory whenever we run our vulnerable function whether or not we use it or not and you can tell that it's actually being loaded because if you were to run it in gdb and then set a breakpoint at main for whatever and you just do print system to print the address of system then you'd see it'll give you an actual address like as you can see system is located at that hex 7ffff7a address and you can also do like print princess or print puts to print all the addresses of the uh the functions that are in libsy so this is how you know if you're a c developer on linux or an operating system how doing this stuff is easier because you don't want to write the actual code that takes your input does the right system calls to print it out does the right formatting you don't want to do that somebody else already did it for you i'll just use their code so what we can do is we can try to leak an address of lib c to figure out hey when lip c is loaded inside memory what addresses it actually loaded so if you were to type in the command vm or vm map in gdb what this will show you is this will show you the actual addresses that everything in ram is loaded at so if you look at the top we have our actual binary and as you see the start address which is that hex four zero zero zero zero zero you saw when we were looking for uh memory protections that the binary had was no pi and as and that every time the binary runs it's going to be loaded at that hex four zero zero zero zero address so we have our our binary then on right under that we have starting at hex seven ffff we have our ellipse c so that's the beginning of our ellipse c and then after that we have the um just the rewritable page of memory and after that we have our linker so our linker is also loaded into libsy then after that we have some more random pages of memory we have vdso which is a whole other topic we have another section of our linker that's loaded in then we have our stack so as you can see the start address of our actual stack is those addresses right there so since the um since with gdb whenever you run a program it's not run with aslr by default those addresses are always going to be the same every time you run the program however if we were to run the program with aslr then the addresses are going to change not our binary addresses like the vol addresses because the binary does not have pi but the lipsy the linker the stack are all going to change so if you were to uh type an aslr space on to like say hey we want to we want to put aslr on now instead of you know have it off then you're gonna run it again on the binary again or check the memory to rerun it so yeah remaps and then you do vm to view the uh virtual memory you can see the binary stays the same but all of the libc addresses are different and all of the linker addresses and the stack addresses are different and if you run it again do vm they're different again so we have to figure out hey how do we actually defeat aslr which this is what it's called where it randomizes the address address layout so a thing with aslr is even though the addresses are random they're not completely random so whenever you're calling a function like let's say for um in your program with aslr you wanted to call the the vuln function if you have a main function and a volume function now if aslr is enabled in the binary or pi's enabled let's just say hype like for your binary not this binary specifically but just for your binary how will it reference the volume function if those addresses are random they typically need an offset right yeah it can't it can't really do that so with aslr it's not completely random in the sense that every time you run a binary and you wanted to find out how far away the system function is from the princess function for example it's always going to be the same so you don't have to do this but if you keep running the binary printing system printing printf finding the difference it's always going to be the same because even though the actual load address of libsy is um is different the offsets for each function and lip c are always going to be the same what this essentially allows us to do is if we leak any address in lib c that we know we're leaking like let's say we leak um let's say hypothetically we leak the printf function it doesn't matter we know we leaked the printf function and we know we have that hex 7f whatever value we are able to calculate the system function we're able to calculate the puts function well we're able to calculate all these functions even though we lead to one value inside ellipse c which is now you can see how memory leaks are very very valuable you don't have to leak all these different function addresses you just link one address and you have all of you know everything inside lib c so how are we going to actually achieve this memory leak and this is where we get into sort of how your binary is able to interact with lib c using the procedure linkage table and the global offset table so let's talk a little bit about you know how functions are being called in left c which is it's not too complex i know a lot of people here global offset table procedure linkage table and think hey this is you know crazy stuff but if we go to gedraw you can see sorry i thought you were going to keep chatting well good to gidra if you go to uh ghidra there's a on the top left you'll see the actual segments of memory and you can see we have bss.data.got dot plt dot dot all those different sections so let's say we were to call the scanf function what would actually happen is we're going to call scanf inside of the plt or the procedure linkage table now if you double click on scanf and gitra it won't actually go to scanf in the plt it'll go to another function but if you go to the actual plt segment inside the program trees the dot plt and if we were to search for scanf there's puts said registry id set buff id there's our scanf so whenever you do that call instruction that call scanf it will put the return address on the stack and it will jump to this address right here which is the hex400580 right there yep now what this is doing is just getting the value that's at scanf inside of the got or the global offset table and that value can either be two things well it gets that value and then it jumps to it and that value can either be two things it can either be the address of the next instruction which would be the four zero zero five eight six which is that push lx4 or it will be the value of actual scanf and libc so whenever we were in gdp and we're doing that p scanf or p system it would be that value that's at that um scanf global offset table area of memory so if we were to go to the uh dot got its dot got plt section and didra right there yep these are the actual the sort of array of all of the um libsy addresses so as you can see scanf what it will do is take the value that's at 601038 which is those right now it's about three zero two zero six zero which is going to be different whenever the binary is running but that that value right there is either going to be the actual address of scanf and libc or it's gonna be that lipsy at plt plus six which is that push for whatever so what we can do is we since we have control of code execution it let's try to find some way that we can sort of just print that value out so with the functions that actually print stuff out that we have you know imported which is puts um i don't know if we have printf yeah we just have puts so this is this is the only function we have that we know the address of because we can just do like a call puts and um it will allow us to leak memory so the way that puts works is puts will take a take one argument and that argument is a pointer to a string so let's say hypothetically we were to call puts but with a value 601038 which is our scanf in the global offset table what it will then do is instead of printing you know 601038 it will print the value at 601038 because puts takes a pointer so we'll actually print out the value of scan up inside of the global offset table which will either be our real scanf address or the address of scanf at the plt plus six which is our push ox4 awesome confusing about that i know it's kind of whenever you get into the global office table and procedure linkage table it can get pretty intense pretty quick i tend to get confused on dot got on its own dot plt on its own and then dot got dot plt is dot is dot global offset table procedural linkage table is this the single source of truth is this where we tend to always go so it's really it's really the dot got plt it's where you pretty much always go okay because with the dot plt the dot plt contains actual like code instructions that are executable right and as you saw with nx whenever you have an executable segment of memory you can't write to it you can read from it but it's just going to be you know assembly op codes so it's not going to it's just going to be pretty much gibberish but with the global offset table it's both writable because we have partial railroad we can also read from it and the global alpha table contains all of the addresses of these functions inside lib c awesome but the plt is what's actually being executed whenever you call it but the values that are being jumped to after you execute the plt are being are pointing to lib c so it's sort of like a jump jump jump like it's just jumping everywhere yeah so now that we know that we have a value inside our binary where we know a libsy address is going to exist let's start trying to figure out a way to print it out so this is where we get into the sort of like return return oriented programming yeah which is a very very cool technique it's it's i mean a lot of people like get into return roth and they're like oh this is pretty cool like i can call these functions and everything but when you really get like down to doing like very complex rob and more advanced draw like you can you could pretty much use rop to make your own um interpreter reverse shell it's just it just gets so whenever you get to the more advanced like oh instead of just calling functions you just program your own program inside of an actual program and it's almost very it's just gets very mind blowing but anyway um let's start trying to formulate a rock chain finding rock gadgets we'll talk about a little bit about what rock gadgets are to try to leak that lipstick address so in layman's term what a rob gadget actually is is it's a sequence of instructions that end in a return instruction that's just the the basic layman's definition you have you know more complex drop chains but in our case it's just going to be hey any set of instructions that end in a return instruction so how do we go searching for these um set of instructions that are in the return instruction we can just manually go through it and get draw but there's also tools that exist um one of them is called ropper one of them is called rock gadget i believe that rob gadget comes with pawn tools so it's just rough gadget yep and it's going to be rob gadget dash dash binary it can be our volume now you can see here's all of the all of the uh gadgets we can use so these are a set of assembly instructions there are some that ends in like jumps and everything but in our case those aren't going to be very useful but it's pretty much all these instructions that just end in rhett and jump and all these different things so for the actual rop gadgets we're going to need we're going to need a rob gadget that lets us control the first argument of a function call because as you saw in order to leak that scanf address we're going to need to do puts and then the address of scanf and the global asset table so whenever you get to like the assembly assembly the first argument of a function call is going to be in the rdi register you can um google the actual it's called um x86 64 calling conventions and it'll tell you hey whenever you call a function this um rdi needs to contain the first argument rsi means the second argument rdx and then it just keeps going there's a big list then after you fill up the registers you start putting values on the stack but all we care about is rdi because because puts only takes one argument am i calling that right x64 calling conventions yeah yep yeah there should be uh wikipedia x86 calling conventions this contains like a whole list at the bottom of it'll tell you like the historical background there's so many different types of calling conventions but essentially what calling conventions do is just it's sort of a standard to say hey whenever a computer is passing arguments to a function call this is how you should do it you don't have to do it but this is how they're going to do it like for for our case we're using we're on x86-64 and we use the gcc compiler so it's going to be the system v yep right there and there's our argument list so rdi is the first rsi rdx rcx r8r9 and it gets to the mmo mm0 and through 7 registers which we don't really worry about as if you want to pass like floating point values and everything but after r9 parameters are just going to be put on the stack so if you have 10 arguments in a function call it's going to be those registers then the rest are going to be put on the stack so there's the calling conventions we have to find some way now of putting that value inside rdi so this is where our rap gadgets come into play we want to find some gadget that modifies rdi whether it be like a move something rdi or a pop rdi ideally a pop rdi it will make it easier but essentially something that will just modify rdi so if you look we got pop r12 r15 rvp and there there's the pop rdi so what we want to do now is at the end of our exploit we want to call this pop rdi so this will allow us to then edit whatever is in the rdi register so just save that address yep pop rdi and there we go easy enough easy enough yep so what the pop instruction will do is it will take whatever is on the stack and put in that register since our buffer overflow has control of the stack after that instruction we're going to have to pass the value put the value we want to put in rdi so we have our pop rdi then whatever value you want to put so we want to put that yeah that's that's 6010 that hex0060 so we can just call this scanf at the got cool so what's going to happen is it's going to execute that pop rdi instruction then it's going to put that 601038 inside the rdi register then after we do that it's going to hit a red instruction which means hey we're at a red instruction it's going to still look at the stack for what value you want to jump to so we got to put another value that we want to jump to so this is where we need to call the puts function and the way we can call the puts function is how like your program calls a puts function what it will actually do is it will actually jump to the puts at plt instruction or address so if we go back into gedra go to the plt look for puts and we can see that there's our puts right there if we just jump to the hex four zero zero five four zero that's essentially we're calling puts so we can just call it like puts at plt cool all right we got we got those constants sorted out so let's start actually building this rock chain so for this rock chain we'll get to we'll get to the packing soon am i going ahead of you i mean if you want to yeah it'd probably be it would probably be good to uh just pack the values whenever you're storing them in variables it's just up to you whatever you personally like but um in this case since we're working with a 64-bit binary we're going to use p64 you're totally right okay so yeah if you just want to leave that um do you tend to do it like after you've built your chain or you do it for the variables how do you usually do it so what i actually do is um pencils is pretty much more black magic than gdb but um essentially with pwn tools you can automate the whole finding of addresses which i'll get to after we do it manually because it's always good to know how to do it manually before you actually automate everything because if you automate it and you're stuck in a situation where you can't automate it then oh well because you know how to do it manually and on and automate it it's it's better in the long run so that's what i generally do is i just you know use phone tools magic to find the addresses which we can get to after but um in this case let's just uh leave it how it is we'll do the packing inside of our actual payload rock chain so the first thing we're going to need is we're going to need our what i like to do is just make a variable called payload this makes it easier building a rock chain and the first thing we need is our junk which is our a's up until the yep then after our junk we first need to call the pop rdi to edit to fill the rdi uh register which is going to have to be the p64 we're going to pack it then after that we're going to do the uh scanf at the global offset table because that's the address we want to actually leak then we're going to do the puts at plt which is the call puts is that fair yep that's good so now that we called puts that plt after that function ends it's still expecting a value on the stack to jump to so we're gonna have to put another value on the stack that we want to jump to so if we just leave it blank the program's gonna crash we don't want that we want to have the value leak but also control it so just for simplicity's sake let's just jump back to main act as if you know this is some just jump back to main so if we go back to the binary in gedra go to main i need to scroll down yep there's our address of main that's all we need yep so we're gonna p64 again but so what this is doing is this will make this makes it so that after we delete the address we just go back to main act as if the program just started back up again so it doesn't crash gotcha now after that we have to we have the payload constructed now we just have to send it to the binary so we're going to do p dot sun line or you can i'm going to bring this all together because i tried to separate it a bit and then we'll take that process and send it yep so now we're actually going to send our payload to the binary so cool let's try running that all right okay now you can see it printed our a's and i printed some ran some weird values so what those values are is it's the address of scanf and lib c however it's trying to print out as ascii and if you look at the ascii table like hex 7f isn't an actual you know printable character so it's just going to print out like that backslash x it's going to try to print it out but it can't so now we have this memory leak how do we actually programmatically use it use it to our advantage so back in the pawn tools script let's try seeing if we can just put that in our script and store it in a variable so let's make a leak variable and then say it's just p dot receive line so just say hey receive a line of input and sort in the leak variable and after we do that under there we can do log dot info so we want to print something out and we're gonna have to use an f string here then just print out link i'm just gonna put in our uh curly brackets so we can print out the link variable uh there's a cool trick you can do with f strings like having an equal sign right before it yeah you can do that i mean we're not printing out anything else so we know that one value that we leak is going to be the value we want but i'm going to do that just so it um doesn't like me is it the other way around the other way yeah that will typically display so it should be up on the top oh you're right yep thank you good call the reason i like using leak or log.info instead of print is because with print it doesn't put any identifiers so you might actually mix it up with the actual program output which makes it harder to see but if we do log.info it prefixes the string with that curly brace or that square brace star which makes it easier to identify now i notice we're only grabbing that first banner yes so you need to do another p receive line because instead of grabbing the first banner let's grab the uh let's try seeing if hey if we receive the next line if that'll actually print out our leak and as you can see notepad just prints out our input during another receive line let's try doing it again and there we go much better now we just have a new line at the end yep so now we have to actually format it into something that we can use so the first thing we have to strip the new line so that strips the new line so now that we stripped the new line um if you look at our leak again it will just be the actual value without a new line which is what we want just the raw value and it's asking for so now what we actually have to do is this is actually in a bytes format and we want it in an integer format so we have to unpack it you saw how with our p64s we were packing the integers into bytes now we have to take the bytes and unpack it into an integer so you have to do a u64 but the thing with um u64 and u32 and all those is they expect that the string is actually however many bits you're specifying so for u64 it's expecting hey this string is four bytes or eight bytes and then if you look we're going to say hey unpack requires a buffer of eight bytes so what we can do is we can just safely prefix it in this case this little ending is actually going to be the suffix of it but with no lights so what we can use is the function l just or the method dot l just which means hey we want to adjust the string pat it with some bytes in front of it and we're going to do eight which is the size so we want to say hey we want this string to be eight bytes now and we're gonna prefix it with null bytes or in this case since it's little endian make it the suffix okay so then if we run it and unpack it we have that big decimal value if you want to print it out as hex you'll see it actually looks like a hex 7f blah blah blah value well look i wonder if it'll let me do that nicely with the equal sign there i think it will yep yeah okay so yeah there's our there's our leaked value so now what we can do is we can store that in a very we can um we already stored in elite variables so it's fine but we have our set buff the actual set buff or not set buff sorry scanf inside lib c awesome so okay so we got scanned up inside lip c now what we need to do is we need to calculate the offset between scanf and the function we want to call which is system okay so there's two ways you can do this um you can either do some algebra to find the difference between scanf and system figure out that offset and then take that leak minus the offset you find system or you can um just play it safe and say hey let's just find the base address of lib c so it makes calculating offsets easier this way if we if in the future we want to call other functions except for system we're able to more we're able to easier we already found the base address of lib c we just have to find offsets of that base adjust we don't have to actually calculate the difference gotcha so we have to do now is we have to find the actual address of syst of scanf in our libsy that isn't the real address loaded in but the actual address in the binary itself so you can either load libsy and gedra and analyze it but that will probably take you know a good two to three minutes inside a vm or you can just use read elf read elf is another program that will print out the symbols of of a binary so if we do read elf it will print out everything but we would just want the symbols so we're going to do dash s and here's all of the all of the little c symbols we only care about scanf so let's just grab for scanf because it's going to take a while to search for all of that so there we go now a lot easier to search so there's our scanf and we see it's 7b0b0 so if we take our leaked value subtract that 7b0b0 then we have found the actual load address of libsy the actual base address which will make calculating other offsets a lot easier is that fair yep cool so now what we can use is we can use that base address ellipse c to calculate the address of other functions and the function that we need to calculate the address of is system so we can use that read elf again to find kind of the offset right yep so there you go we got that four f for e0 now if we do the base addressable of c plus that four f we have the actual physical in memory aggressive system awesome all right cool so we have the aggressive system there's one thing that we're missing and that thing is the actual bin sh string yeah four slash bin four slash sh so what you can do is you can just say hey why don't we try to like read in put in sh into our payload use that whatever but fortunately with us the way system actually works is it calls exec l forward slash bin force sh and then your command so the nsh string has to exist inside ellipse c in order for a system to work so we know that the minus h string is in lib c let's try finding it and to prove that you know it's actually inlet so you can just run strings let's see and then grep for ben sh yep and you can see it actually returns successfully now to actually find the now i have to actually find the address of the nsh in libsy so this is where we're gonna have to get out get jira and open up libsy fortunately for us we don't have to analyze it we can just open it up and search memory so it's not going to take you know three minutes to analyze and for analysis just click no click ok now we're going to have to search the memory so you can either go up in the top to uh search or you can just press s now for the format we want to find a string we don't want to find a hexadecimal sequence so we're going to click string for format my virtual machine is getting annoying on trying to move windows i'm clicking on things all right and then just then sh nice search all and there we go we have that right there so if we click on that now you can exit out of those windows and then cool you can see we have that that bin sh and we have the address of it so there's the address of nsh 2b40fa right uh yep 2b40fa now that's going to be from the base address of libc correct yep cool okay so we have everything we need to do an actual rhett's libsy we have our aggressive system we have our bandsaw string address sweet and the other thing is the program jumped back to maine and now it's ready for us to receive input so this is where we construct our second rock chain but instead of doing the pop rdi scanf and everything to leak live c we're just going to do pop rdi that been sh address and then the address of libsy and we're also going to have to pack that with pieces before thank you so since we kind of cruise through that i'll offer some other uh top coverage we'll use junk to again get back to the offset where we know our instructure pointer will end up going uh because of the buffer overflow we'll use pop rdi to supply an argument to a function that we're going to end up calling uh and pin sh address is just going to be the string for bin sh and we're giving that to system so system is going to end up being the function that we call but before we call it thanks to rob we just do need to prepare that address and that's why we use rdi and get that address that we just determined with some rhett to libsy math cool then we can just prepare that payload i think yep pray that payload send it off wow and all looks good i think now that will call system and system will kind of block because we'll just interact with it so we're we're done yep so let's try try running it see what happens moment of truth i fail so we've got pop rdi we've done previously yeah error it might be because you're trying to overwrite oh yeah you did p dot join you got dot join payload but it should be second oh you're totally right haley thank you so much that's why you shouldn't change your variable names okay okay but we've got an end of file now what we wanted what's expectation fault so now we're going to get into the fun stuff try to debug our rap chain yeah so fortunately for us pwn tools makes it very easy what we can do is after our p equals process we can do a gdb dot attach and then p so what this will do is this will run our binary but then attach gdb immediately after all right now since you're using a terminator you might need to do a little funky stuff so uh at the top of the uh ponce script you're gonna need that context oh it actually did it yeah i wanted to check but it looks like it behaves okay yeah all right so now let's just um set a breakpoint at do stuff or let's go to um not a breakpoint i'll do so let's go back to gedra find out where the uh do stuff return is like the return instruction it's up on the uh if you go back to gadgera oh you're right top left yep you can just x out of libsy yeah great so let's go to do stuff search for do underscore stuff i hate when my vm does this all right and then click on that return then you can see it.hex zero zero four zero zero seven seven zero right there yep so copy that address oh is it just acting up are you yeah all right so it's just going to be b star ox 4 0 what was it zero zero seven zero zero fair yep cool now do c for continue so we're reaching our this is our first rock chain that's gonna leak we have the pop rdi rep so if you just do si enter and now it goes to the pop party direct just press enter again because gdb will if you just press enter in gdb it will run whatever previous command ran then we get to the ret then we do actual puts we don't care about this stuff it's just going to go execute puts inside of libsy so we just continue um yeah just continue uh i'm still sting single stepping yeah you need to see for c for continue yep our breakpoint will still hit it yeah okay now we're at the pop rdi so si yep pop rdi let's see now let's examine to see what's rdi to do x uh four yep that works x4 slash gx and as you can see something's wrong so let's try to figure out what what went wrong here so quit out of that all good and gif yep cube okay there you go so now if we go back to our tool script so what we can do to uh debug this is let's this is very common with rock chains about having to debug them because something happens you type in a bunch of code you're like all right i'm so excited and it just said false yep very typical so the first thing we should do is check to see if our leak worked okay under the log.info for the leak is check to see hey do we actually calculate the base address right is that all we need just to check to see the contents okay should be it let's just try running it you can uh yeah hmm so now we can see what our issue is we didn't we didn't leak lift c right because with lib c whenever you load a library in memory the last four nibbles or the last hex hex digits should be zero but there you go zero so we could figure out why this didn't work by figuring out like hey is the scanf right and everything or we can just pick another address to leak um it's up to you um if you just want to figure out the scan f1 we can figure out the scan f1 so we're gonna have to do is we're gonna have to run it with gdb figure out hey are we leaking scan off right pretty much just you know the whole debugging shebang of let's try try to figure out what's happening because something doesn't seem right okay so if we run it open up our debugger set a breakpoint let's just set a breakpoint at me make it easy to just do b and then main and then continue now let's go back to our screen to see what leafs we got so let's copy that at scanf1 which is the hex leak so now if we print it it should say scanf and it doesn't well if you if you do examine you might have to examine this yeah so yeah so we got our scanf but our leak's not right so now we know that hey we're getting the actual leak it's scanf but our base address is wrong just through like trial and error or like analysis we can figure hey is this constant we're subtracting out the right constant so if you look our scanf is actually going to underscore underscore iso c99 scanf not scanf itself right so there's the there's our issue so let's try searching for the iso c99 scanf in the binary with read elf instead of cnf itself okay just trying to just debugging figure out hey what's wrong yeah this is good this is this is a good process it's probably going to be in the ellipses you are totally right i'm sorry let's see i grew up yep uh just do yeah that might be truncating in some weird ways maybe i'm guessing it is truncating it so uh you might do uh just pipe it type it to less so we can search search for it interactively sure i get easier so let's try to search for like two underscores it's probably gonna be two underscores oh god do we have any two underscores i maybe because it says two underscores i soc iso i'm guessing um you could type uh n to go to the next occurrence sure and then capital n will go to the previous occurrence so we have some isos so obviously you can see you know scan that's not a good function to leak because it's getting pretty difficult to find the actual offsets luckily with the way that the global locksmith table is structured scanf isn't the only function we can use to leak we can also like leak puts it's uh the our only limitations for address leaking in this way is whatever's in the got plt i'll get there eventually okay so our only limitations for this is whatever is in here so i think puts is a fine option puts is a fine option let's try puts so let's go through the same thing we put the put that dot and the puts that don't need plt so yep that 6 0 1 0 1 8. you can just change the constants if you want even though it's substantive it's actually going to be yeah great we don't need to do the plt just the got but we also need to find do the offset the scan up offset so let's go read elf and then puts uh there we go that looks much more accurate eight zero eight three zero is it eight zero eight three zero or um eight zero a three zero i think be an issue with it i think it should i think it should be fine it should be fine i guess we'll find out yep we'll run into another wall what did you have in mind what were you when you were thinking uh so are if you saw our buffer overflow would receive input until a new line right line character in hexadecimal is zero a oh however since with lipsy addresses the only thing that's going to be the same as the last three nibbles so that's going to be the a30 so that that 0a might be like 1a it might be 2a it might be 3a just depends on aslr that's true but if it ended like let's say it ended in 0a0a that'd be bad that would cause some issues okay well and it's also the same like let's say if we just say scanf percent s scanf percent s won't read in the white space character or hexadecimal two zero so if you're trying to leak an address that had a zero x two zero in it or your rock chain contained a zero x two zero that's not gonna work and it's very difficult to debug those type of issues because you're like hey i have all this stuff laid out my code is correct why isn't this working and it's because the way my program was receiving an input cool let's try the this can go we can st do you want to step through this or should we just let it cruise cool oh we got another segment it looks like flips press ls so let's look at another segment let's let's see why it occurs this is the old gdb this is the new one so let's see we have return let's see without our stack rsp is now pointing to oh i'm sorry yeah it's pointing to a junk garbage value try to figure out what's up there so let's go back to um my assumption is um that there are what i what i predicted how we had that new line character inside of here that's that's my assumption just based on saying this but it could be something else let's try one that isn't as risky i guess you could try i think i used setbuff when i solved this yeah let's use setbuff yeah but as you can see like just looking at gdb if you weren't aware of that whole new line thing it can be very difficult to debug that because you just see a junk value and you're like wait hold on a second this should be my value that i put there 6 0 one zero two eight for set buff uh two zero two zero yep or yeah two eight sorry now you're good that should be set buff okay and then we can get the set buff offset cool 88540 much better that seems better yep let's try it again we can let the debugger go all right oh looks like our leak went a little bit a little bit wonky little weird numbers let's start running it again yeah if you look at the leak it doesn't start with 7f oh good call so let's try running it again continue that's better 7f how did gypsy look another issue so let's see what this issue is um so we have rsp is pointing to there and so let's try to find our actual payload our a's that we entered usually we can use a uh jeff function called telescope so telescope will it allows you to like pretty print memory telescope dollar sign rsp let's just do minus um 32. uh oh you can't you have to uh you can't put spaces between the oh yeah i'm glad you know that there you go so yeah here's our there's our pretty print you can see our rsp value now rsp should be our address of um address of pop rdi but it's obviously not um our payload is overflowing so let's go back to the pontool script looks like there's some issues there so we have our junk let's look at the first payload see what the sure junk power yeah that looks correct now let's go to our second payload chunk that looks correct do we need something else sane to jump back to after this you shouldn't need it because system will fork yeah um all right let's try stepping through it again okay so set a breakpoint at the stuff so we're gonna set two breakpoints this time we're gonna set a breakpoint at do stuff and we're also gonna set another breakpoint at deuce stuff return address because we wanna see what's the layout of the stack before we enter our input and what's the layout after to make sure there's no like funny business going on all right so you said we want one at do stuff yep and another do uh you can do um disassemble and then do stuff do stuff now to make this easy we can just do yep you can type that in d star ox there you go all right now if we do c for continue this is our rock chain that's going to leak so if we just do si we can step into it step into it make sure it does everything correctly so rdi so now we're at puts let's well step again yep and then now we're jumping to uh puts so let's see if rdi contains the actual value we expect it and if you see at the top rdi is there so it prints set buff which is correct so let's continue now just for a sanity check let's go back to see if the link is actually processed interpol scripts [Music] so yeah that looks all sane but it'd be good to double check those addresses oh should we double check this that'd be good just double check yeah sub buff good print that all right that that's not gonna um display correctly because it's the there's no symbolism yeah the base it just kind of just won't know yeah the base address is just there but it looks right you can check it with the via map if you want to but it looks it looks thing um let's let's just try vmware so yep so yep it's that seven f seven d one one three two c c0 7f7d yeah perfect okay so that's okay now let's um let's see if our system address is actually correct so let's do print system now let's do let's try to find the we don't know we didn't print out the system address right since gdb will let us do some you know basic arithmetic we can do p and then system minus the base address of lift c to find that constant so it's ox for f for e0 so let's look it up tool script to see if that's right 4f4e0 cool that's correct so everything looks great let's just keep stepping through it so let's so step until you get to do uh other continue i think well not continue to do um ni which is next instruction but it won't go into college like whenever there's a call it won't step into the call i'll just step over okay so let's go right before it calls scanf which will receive our input so here we have the scanf then we have rsi which is our string that we want to actually scan in so now what we want to do is um yep so if you look at the bottom you have the scanner pht it'll just print out rdi and rsi so we know that that our string is going to be contained at whatever rsi is pointing to so let's just try copying the rsi value all right now let's do ni to step over the scanf so just received our input now let's do telescope again and let's do that value that we had the uh yep so as you can see telescope didn't print enough so if we do telescope space and let's say we want to print 64 instead of the default you might need to scroll up a little bit so there we have our input input input okay rbp right there so pop repeat now we have that we have the pop rdi but the pop rdi is pointing so as you can see what it should show after the pop rdi is it should show our bin sh but it doesn't show up in sh so that tells us that our bin sh is wrong now what we can do in um gdb is you can actually search memory which is very convenient or uh jeff yeah so i believe it's search and then um it takes like a start address and an end address and then whatever string you want to search um so let's get the beginning and end of libsy well that's that's the beginning and end of the first segment ellipse you want oh so it's going to be all the way down right cool good catch and then sh yep you can't find default source file you might have to wrap it in quotes um which part [Music] i keep on creating the syntax that's all right [Music] maybe you don't even need to search pattern or just grip that's pretty awesome okay prep oh there we go so the address of libsy or bin sh you can see is oh that's actually great i didn't know about grip but um it's actually the 7f7d114e that's actually a pointer to a pointer that's pointing to then you know you got pointers and stuff now that address has a null byte in it and that scares me well the thing about that is that's a pointer to a pointer we want the uh 7f 7d114e one uh zero one zero one okay because then if we just do like a print and then that value you'll see it actually you don't have to do a minus just print or do uh examine s sorry oh that's not the nsh i think it's two it's it's uh this address to that address try yeah try printing it out there we go yeah so that's it so that no bite still spooks me even yeah the null bite still spooks you however our rock chain has had null bites since the first one oh because with the scan of as i said it scanned until a new line oh not a new line or an old light so now if we see it's that 7f um 7d let's try to find the offset see the that's right yeah that's your god so it's 1b40fa now let's go back to our pawn tools script see if that's it and no it is not so there's our issue i had a typo we found we found the bug are you telling me that i mistyped something vitally important as you can see how we track down that bug just by doing some sanity checks yeah okay well it's very it's pretty difficult you know if you're not if you're not used to solving these challenges using gdb yeah like just stepping through with gdp you can see how you get a cell phone and you have no idea why it's like defaulting yeah but now that we did subsidy checks in gdb and printed out some values we could easily just track down so that's why debuggers are very important when doing these challenges the gdb is definitely absolutely critical here it's very yeah it's very a lot of people don't realize they'll just try to like write it look at the uh disassembly write it do it it didn't work try something else try something else even though as you saw you just put a two instead of a one yeah so let's try it i can just continue here yep let's let the debugger go now let's just try doing ls i'm still tripping over something all right let's try um setting a break point at um the do stuff return again so you can do disassemble do stuff let's set a breakpoint right there yep b star ox continue so this is our leak rock chain we can continue okay so now here we go moment of truth so if we si all right we have our bit sh on the stack then if we si we pop it in then we have our ret si now let's see what's in rdi rdi is the actual address of lipsey and you're going to love this you want to know why what's up the reason is sega faulting is because libsy is using our system's linker what so your exploit works but the problem is system is seg-faulting itself because it's trying to use the system's linker which is too new for the lib c so that's why you're getting that segment so if you i'm pretty positive if you run this against the remote it will work uh it might you might actually um there might be an issue you can try to get to a remote which is the the guy who does banax or anybody who does bin x is always this issue but turn on your remote if you get the a shell good fianna file then we got that issue which is our good friend's stock alignment our good friend stack alignment god i hate him yeah so we have stack alignment which i'm guessing because it's always stack alignment it's always so quick quick fix just go into uh you can either use drop gadget you can go into gedra just search for any return instruction just all right nice and easy yep let's uh let's do rob gadget again and i am going to grab for a colon and a red so i know that's the very very first thing there you go so this guy looks pretty good four zero zero five two e this is going to go before the system yep so before the system put your p64 p64 oh thank you we're a 6-bit architecture now okay let's try that now the reason that this works is because we are still doing rop all we've done is we just use our pop rdi to get that into the argument rhett will just do nothing but let us continue on to the next call so here's so stack line let's talk a little bit about like what stack alignment actually is and why we put a red instruction there yeah so with um more modern ubuntu lip sees i believe it's like 2.27 and up um the lipstick will actually have certain instructions that will um require that the stack pointer be 16 by the line meaning that the stack pointer's last hex digit is zero and if that digit is not zero then it will seg faults just based on how those instructions operate okay so what we're doing when we do that red instruction a return instruction will pop something off of the stack which will then change that stack pointer from the last byte being or the last nibble being a 0 or eight because pop will just take whatever's on the stack increment rsp i believe yeah increment rsp by eight which will now you know instead of it being eight it will now be zero when we reach that instruction that requires that the stack be aligned cool let's do it i think that if that's confusing i can try to phrase it better but in in my mind it always seems like okay adding a little bit of padding so things become back to normal in this case we're just padding with more instructions like a return is that fair to say i mean it's not padding in the sense of a knob sled right it's more of just it's more just a nuisance than anything but uh it's just that it's it's more of a nuisance um you're just trying to make it so that whenever you call a system function the last hex digit is a zero and the way you can do that you can use pop instructions you can use write instructions pretty much any value that just edits that rsp register okay in this case we're going simple which is putting your red instructions okay all right well let's try this thing so i think we're good yep let's go bold and not attach the debugger well as you saw with um the linker issues it's not going to work locally is is it are we positive it is a linker issue um oh wait you ran it locally it might not be a link or issue i think it really was just stack alignment because i'm always in the same i'm i'm taking 2004. yeah when i saw it um when i saw it segful i didn't see any things in the instruction pointer that pointed to stack alignment but what do you look out for when you are trying to look when you when you said something that would point to stack alignment so what points the stack alignment is you seg fault on an instruction that is like a move apps instruction there's i forget what the it's called but there's cpus have you know your regular move pop and everything instructions but they also have like stuff like move apps they have x86 is a complex you know architecture but um like in and this you don't have any move apps you just have basic assembly instructions that don't care about the uh the stack pointer but in live c specifically system also printf um there are these instructions that exist [Music] i'm trying to find the correct term for these instructions well yeah that's essentially what it is okay certain instructions just you might find it if you just step through system okay i'll jump to system yeah si then you keep going move move all these are fine all these work perhaps toss that's fine that's gonna probably take a while to execute oh jeez i could do and i still or no uh you might be able to do ni oh maybe not no um all right that's fine yeah we made it through wow guess is so awesome yeah that's it the uh compare exchange i'm pretty sure that's one of a uh that's an instruction that needs an align stack i think i'm not positive though but i know for a fact move apps you need an align stack it's uh do do these are there's a move dq there it is move dq you see how it has the uh x mm0 yeah that requires the uh stack to be aligned ah just because of xmm0 yes because you're using those xml xmm registers and those are the ones that are like based off the stack it's not so what it really is is um they're registers that are designed to hold floating point values okay so what they do is they take your integer value but they do some conversions and store it into a floating point register and with the way that works since floating point registers are very weird like the whole the whole conversions and stuff it just requires that the stack be aligned cool so this is our exploit that should run remote there we go all right cool so after a decent amount of time and debugging we did it with a bare bone basics baby rhetolipsy attack well yeah i mean it's a it's a baby retze lipsy um you get people who've been doing this for a while they could solve it without even debugging just write a script and solve it um i know a guy who actually wrote a tool which will automatically solve rectum ellipses challenges oh my gosh you should give it a binary and ellipse and if you're feeling feeling lucky you also give it the ip and port and it will give you the flag that's awesome because it's just it's a basic challenge but the thing about red to live c is it's good to go very into detail about how everything works why we're using the got to leak addresses why the got actually contains lipstick dresses because part of that stuff is very foundational when it comes to more advanced stuff like more advanced drop chains um format string vulnerabilities even some heat exploitation just being aware of how your person your binary that you create interacts with lib c it's just very important to understand like as as i've said you know people who have been doing this for a long time they can just look at the binary and then just write the script yeah and solve it yeah because it's a basic challenge people do a bunch but it's really great to have that foundational knowledge of i just mentioned whenever it comes to the more advanced stuff well sweet so it may seem like you know a basic challenge but we and we went to a lot of detail yeah definitely but it's just good to have that detail cool well hey that was awesome thanks so much for for walking through all that uh i realized we we took our sweet time with that one so i think we we definitely don't need to do any more today i mean if if you want we can i mean as i said like i'm on break yeah i got nothing going on like it's just up to you i know i can show you how i'd solve this using a bunch of tone tools foo if you want oh yeah we could do another challenge is up to you are you in a spot to do a little bit of a demo and you can just like rapid fire cruise through however you had solved this just to showcase it i'm going to stop recording just to have a different video file for that and also as i said like if the whole walking you through it didn't work out i can just walk through it myself i mean that was like two and a half hours of pretty exceptional uh knowledge so i would like that's what i that's what i wanted to like do is just spread knowledge not just solve a challenge yeah a lot of these write-ups you see they're just solving the challenges they're not spreading the knowledge yeah like if you like a lot of challenges don't mention the stack alignment yeah challenges don't mention debugging yeah and that troubleshooting portion so all of that was pretty gold and i'd like to i do not understand why obs is seeing your audio come through but it is not being saved into the footage uh i have zoom going so that's fine but the first like 20 minutes of experimenting with bone in it uh i might just have to hokey pokey but whatever i'm glad we caught that sooner rather than i mean if you want to talk about pawn in it it's definitely a great tool yeah but i as i said i like going through not only the manual but also the automated because if you don't understand the manual then you can't understand how the automata works yeah that's why i did that basic you know let's go grab these addresses using redelp let's go grab these addresses out of because you want to understand like what you're doing and why you're doing it did you want to do a little cool demo breeze through is that all right yeah sweet all right ready for me to share my screen yes all right you see everything okay i do good font size yeah yeah perfect thank you all right so i got the challenge and lip c um i'm just going to use pawn in it to make it you know easy let's look at the linker unsure let's see i'm just going to remove the solve dot tie because i don't like it um patch elf interpreter cool so we got the binary running so now just to uh have the binary opening goodra i'm gonna open up kidro all right let's import it just to have engager if we need to reference it analyze so the great thing about phone tools is pencils does a lot of the automated address searching so we already know that the overflow point is 136 bytes so let's just start making our python scripts three okay process okay so this is how you normally just set up a poncho script but what we're going to do is even though we're referencing the volume through a path and process we can actually interact with it statically so let's just do a context dot binary equals and we're going to say binary which is another variable which is going to equal volume so what we're doing is we're saying hey we're going to make it so that if we need to use shell code if we need to do any um other things that are architecture dependent um pawn tools automatically saves that's that information so if we just do shellcraft.catflag it will give us 64-bit helicode not 32-bit child code because it can read the architecture of the binary and also with binary if we need to reference it in any way we can do that so now that we have this sort of template set up another thing that we can do to interact with the binary is stored as an elf object and what this will allow us to do is it will allow us to um search for addresses grab values out of dresses do all that fancy stuff so let's just call it um um von elf and it's going to equal elf and then we have our binary okay so now this should be able to run oops solved and save it of course so this should run perfectly let's put a p dot interactive at the end all right so now we can do with this full stuff is we can reference addresses as i said but we also want to bring in the lip c so let's just say lip c is equal to elf and then we have our lip c dot so dot six cool that should run fine great so that's all working now to formulate our actual payload we're going to say padding and we're going to have our a's which is 136 okay so this is you know as i mentioned earlier the actual padding until we overwrite the instruction pointer now let's just make a payload variable and say it's equal to our padding so after we do that anytime i want to reference our actual rock chain or payload we just have the payload variable we don't have to like say hey whenever we send it payload and padding it just makes it easier to um work with stuff so the first thing we have is we need to put in our pop rdi gadget now pencils also comes with a thing called rop which is another sort of module so we can say vuln rop equals rop and we can pass in our volume elf now what this will allow us to do is with pwn tools we can search for rock gadgets so we don't have to use rock gadgets to search for raw gadgets yourself so payload equals padding now let's do payload plus equals and then let's do volume rop dot find gadget and then in here we send a list of what our data we're going to find is so it's going to be the pop rdi then rep now what this will do is this will return a list of all the gadgets for pop rdi we just want the first one so we're going to do index 0 then we're going to p64 that so what this will do is this will find the address of the pop rdi gadget pack it into 64 bit and then append it onto our payload then after that we're going to do our um global offset table for our set buff so 364 then we're going to use our volume elf okay then we're going to symbols or not dot symbols dot dot which is our global offset table and dot set buff so now without having us go into gidra and search for a set buff in the global offset table we can just reference it using the volumel dot dot set buff you could also use puts if we wanted we could use whatever symbol is in the global offset table so we have our dot we have our global offset table address now we need our phone elf dot now we need our plt so plt and puts so now instead of searching for gizzard for puts at the plc just use pen tools then after we have that in our rock chain we do payload plus equals p64 we want to jump back to main i'm going to do volume elf dot symbols dot mate so just like that we formulated our opt chain without having to manually search for addresses nice then after that we can do p dot sun line just send our payload so now if we run this we can see we have what we had before where we had our a's and everything and then our leak now before you actually saw how in order to grab the sleep we had to do a bunch of uh receive lines but to uh make this easier for us instead of doing p dot sun line we can do p.send line after and we can say hey after we find this ver exclamation mark send our payload so it's going to do a pdot receive until vr then send our payload so that gets rid of that vr in our payload then after that we still have this that we need to receive so we're just going to do p receive until here p dot receive until but also there's a new line that's sitting back here which we don't see so we're going to have to put a new line and if we run it we see next we have is our address so we didn't have to do p receive line guess and check we just did p dot sunlight after and receive and tail now we can say our leak is equal to p dot receive line when you do log.info then you can see we have our leak we just have to strip the new line and unpack it so we're going to do that strip we're gonna do dot l adjust to make it eight bytes and we're gonna put null bytes d64 so that should be our um setup oops i'm missing uh and there we go so there's our setback leak nice all through phone sold without having to manually put in addresses now after we do that we have to do this thing called rebase the lib c remember back when we were doing our manual sort of exploit script we uh we had to calculate the lipstick base calculator offset so we can do is we can say hey let's just rebase the lip c using this lip c we have right here so you need to say hey lip c dot address okay rebase it it's going to be the leak which is our set buff minus whatever ellipse c dot symbols dot set buffers so all this will do is just rebase our lip c so that now whenever we do lip c dot symbols it will be the actual address of let's say lipstick.symbols.printf it will be the actual address of printf the c dot symbols.system the actual address of system that's cool which is very useful you don't have to manually search for the addresses you can just reference it in consoles so if we just do log.info f lib c base and then we do hex let's see address you can see we have our lipsy base awesome so now after we do that we're going to conduct our second drop shape so payload is going to equal padding again then we're going to do payload plus equals and we have to do our rop gadget drop gadget find again like up here fine gadgets now remember for rdi we actually put the address of bin sh and we found that through searching in gidra well funny enough you have to do it in tone tools nice so instead of opening up json and finding been sage we just do payload plus sql lib c dot search and then lift c dot search invites nsh so this will search lib c for the uh address of nsh but it actually returns a generator so we're going to need to do next on that so this will find the occurrence of or the address of then sh and libc and since we rebased the libc it's going to be the actual address of nsh in memory while our program's running and after we do that we just jump to system so we're going to do ellipses.symbols.system oops and after we do that after well after system it should be fine but since we have stack alignment we're gonna have to put in an arbitrary red instruction so we're just gonna do use our wrap and pencils again p64 volume rob and as i said it's going to turn a list of all of the addresses that have a red instruction we just want the first one so now if we run this we have it uh oh we forgot to send our payload sim line payload i always forget that now if we run it we have a shell nice that's awesome all through consoles no manually searching for addresses and you can see how like to take this a step further how like the great the people who just do this a lot are able to just whip out a pencil script like that yeah that's super easy without even looking at it they just look at giger once that's it like we just all the only thing we needed in gidra was this uh 136. that's awesome you can also see how people you know decide to take an extra step and actually automate the whole thing but yeah super cool use it with tonsils which speeds up a lot of the manual labor holy crap this was awesome took a took a little challenge here and just tore it up and i think got everything out of it doing a manual analysis going through troubleshooting and some other lessons learned and then kicking it up with some automation heck yeah yeah sweet so pencil is definitely a great resource so it sounds like the takeaways are gdb and gef or some other extension seemingly guff is doing really well for gdb and pawn tools are rock stars i mean i've been doing this for a while and all i've really used is just pulling tools judy and jeff like do uh do you tend to do guidra most uh or are you in like ida or binary ninja or r2 so yeah um i don't use radari 2 like at all um i just when working with the actual binary it's just i don't want to be fumbling around on key shortcuts to print stuff out like i just wanted to be in front of me there like as you saw whenever we were going to the actual plt and going to the plt we just clicked on a button and we were there we didn't have to just type in some fancy like seek oh is this it is this it um i use gudra mostly because one it's free um ida is like i think a 1k per license yeah yeah it's pretty expensive i don't i don't do this professionally so but um i also don't use the binary ninja because again it's paid i just do this as a hobby and um there are other free ones out there like hopper um cutter which is a graphical front end for radare i typically stick with the gedra because it's more supported and whenever you're getting into more advanced stuff like more advanced reverse engineering where you have to like rebuild structures um it's very useful for making custom types and all of that fancy reverse engineering stuff gidger by far is ahead in all of those tools awesome well sweet i think we should call it at this point we've done a ton i know your voice is probably getting getting a little tired of it so thank you if it's yeah it's a lot i mean i really just wanted to emphasize you know the debugging aspect because we took this very simple challenge and you can you can just walk through a challenge and be done with it really learn how to solve it if you get to another situation where oh something is different will you able to solve it do you get seg faults randomly just you know going through the whole debugging process cool this should be an absolute ton of content so i super duper appreciate it it will go well in the fundamental uh beginner level stuff for for pico i think this is really good for folks that are interested in this so again and again thank you uh maybe sometime in the future we can tackle another one of those crazy hardcore stuff check out the web browser yeah yeah yeah yeah middle schoolers are doing web browser exploitation apparently i mean that's insane sweet thank you again and again and again um but hey don't hesitate to reach out uh if you want to do this again or maybe sometime in another week or any anytime else yeah i mean as i said like i'm available open i mean i i mean pretty much anything like for the pico challenges if it's just you know other stuff like one of the most difficult parts a lot of people say binary exploitation is difficult and it's not that it's difficult it's just that there's no good resources out there right like you can find tons of resources on web exploitation and everything but if you want to get into binary exploitation you're either doing the intel instruction manual or whatever yeah thanks man uh i guess i'll catch up with you later i'll let you go there's a lot one but if you want to know more i'm always down i super appreciate it thanks so much matt yep take care everybody all right take care [Music] with you
Info
Channel: John Hammond
Views: 179,646
Rating: undefined out of 5
Keywords:
Id: tMN5N5oid2c
Channel Id: undefined
Length: 132min 40sec (7960 seconds)
Published: Tue Jun 08 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.