 Hey folks, Adam DuPay here, and today we're going to be looking at the ponable.kr level simple login. Before we do that, it's after Defconn Qualls, so I need to take this opportunity to apologize to everyone out there who had to suffer through the level Atom tune. That challenge was in no way designed by me, and it was 100% Zardis aka Jan Trojus-Dashvili, so please, please direct all of your hate and blame towards him. So today we're going to be doing a live hack of the simple login level, so let's look at what we got. So, simple login worth 50 points, it says, can you get authentication from this server? Download the executable from here, and it's running at netcatponable.kr 9003. So I've already downloaded this, and if we go to the netcat here, it should, I see, it will. So we can see it says authenticate, I type something in, it gives me a hash, you can do it again, wrong length, interesting, wrong length. So I just happened to hit the right length the first time, that seems kind of sketchy. Okay, well at least we're seeing with different inputs that the hash is changing, so that tells us maybe something. So now that we've played with it a little bit, let's go over and start poking around the binary. So we run file on it first, we see that it's an L32 bit executable, it's statically linked, which gives us a hint that this might be some kind of Rop style exploit 2.624, not stripped, which is important because we still have some simple information. So that's files, if I run a good old-fashioned checksack on this, you can see that it's not a PIE, it has NX enabled, which means, oh interesting, so it's got non-executable stack, it has a canary, and partial railroad, so this is protection on the global offset table. So the canary is going to be interesting, that means we're going to somehow get around that, but maybe first impressions are wrong, maybe it is some way to try to get around this authentication check, or get that to return true or something. So that's checksack, let's do good old-fashioned strings, type that through last, doesn't seem to be anything interesting, okay, well, that's not correct, there we go, there should be the string authenticate, ah congratulations, you are good, hey that's always nice, so it looks like that's the success message, so if we can figure out how to get there, that's probably a good thing, BNSH, so it probably will call BNSH for us when we get that, so we can just cat out the flag, hash colon percent S, so that's the hash string, that's being done in here to get the hash, it has this F87CD61AA7FE, huh, interesting, so maybe that's some kind of hard-coded cache, here's the authenticate, here's percent 30S, so it looks like it wants 30 characters, and we can see that this actually looks like strings from openSSL version 1.0.1e, and then here we have some, so BIO libc, this is some, a bunch of libc functions, so if I look at this, I bet this is a long, yeah, so almost a full Meg, so we booted it up in Hopper, so we can kind of get an overview, we can see that there's a lot of calls here, a lot of calls, let's see, so we need to find this front, in fact, let's just work backwards, so we know that the first thing it sends us is this authenticate, so if we look, this is an ASCII string, so if I look, 0%20X is also a string for sure, or 0%02X, so that outputs it padded with hex, so congratulations, you are good, just so nice, okay, well that's nice, so there's a function called correct, which just looking at this is checking if we're correct, and just as a quick, oh wow, okay, so we have strings move input there, move input into EAX, dereference EAX, compare EAX with dead beef, if it's dead beef, then go here and call system with bin SH, okay, otherwise it puts, congratulations, you are good, so now let's find out where correct is called and with what, so it's gonna call correct, so here, okay, so this is that wrong length check, we can see from here, so we can, ah interesting, oh so that makes sense, that why that our input was sometimes right and sometimes wrong, we can see from this base 64d code, so it looks like, so it calls, client of classic, set vbuffer to, this is just to make sure that it's flushing, it's probably running with x in it, d, so it takes the string, prints out, authenticate, it then takes into, so var 22 into EAX, EAX into var 3c, a little format percent s, okay, so that's where our input's gonna be, so percent 30s is gonna read in 30 characters into there, it's gonna call scanf and then it's gonna call, move, what is input, why is that, I don't do have a name, huh, okay, interesting, so scanf, so it's gonna move, okay, so this is pushing it on the stack, so these variables are incorrect, so it's pushing input onto the stack and then zero and then c and then calling some custom function, which we don't actually quite know what it is and it's also being used up here, so that's interesting, maybe, oh, go to offset table plus 68, I would bet that that's some sort of, maybe a mem copy or something, I'm not 100% sure, let's see, so then zero into, well, let's see what hopper can make up this, that's pretty nice, okay, so scanf into var 22, call this sub 40880482e2, let's see, make sure that I can run this, so let's use run plus x, log in, authenticate, all right, so logged in and again this hello is just, so now, now I can run this with ltrace, so ltrace won't give me anything, why won't it give me anything, because it's not actually dynamically loading anything because it's statically linked, okay, so I can see kind of normal break, access, write authenticate, it's reading in, I know hello works, so I can say hello, it's memmap, that's interesting, that's writing up this hash, okay, so if variable C4 is, so first, okay, base 64 decode variable 22 into variable 28, and then eax into var 4, so, or eax into var 4, if var 4 is less than or equal to C, which is 12, then mem copy, make sure I have my right semantics on mem copy, destination, source length, okay, so copy var 4 number of bytes from var 28 into, oh interesting, oh 811 eb, okay, this is cool, so var 4 here remember is our base 64 decoded length, so copy that into 811 eb 40, which is some buffer, and then it's actually authoring us on this var 4, okay, so things are starting to happen in my brain, which is usually a good thing, but sometimes you never know, all right, so call correct, okay, so basically it's taking our input, it's base 64 decoding our input into this var 28, or probably from var 28 into var 22, I'm not 100% certain, let's look up this base 64 decode, I know this is in, this must be in base 64 decode, open SSL, and open SSL as we all know is known for its nice function names, okay, base 64, that's a gist, gist, there we go, open SSL wiki, basically I just want to know the semantics of what's the input variable and what's the output variable, okay, so I don't care, I don't really care how you actually do it, but I need this return value, remember in auth we need, so okay, arg zero is the length, oh interesting, okay, we haven't looked at auth, so it's the length, so mem copy arg zero numbers from 811 eb 40 into var 14, address of var 14 plus c, so once, I already did this, I'm going to actually just look at this, so number of bytes from source into destination, so copy it from a global variable into var 4c, eax is calculate md5, which interesting, what's the second argument here, c, okay, I may have to dive into that, hopefully not, but we'll return some string pointer into eax, then compare, call this other function, wow, dereference, so fun, joy, okay, so it was not as straightforward as I was hoping, darn, okay, so auth call this, does it jump to global offset table plus 72, do we know what's there, I don't know why it's not decoding this, well there's no global offset table because it's statically linked, so it's probably a static function, okay, I mean we could figure that out from debugging it, oh interesting, okay, well it's getting rid of all these awesome parameters, so check that, okay, so check this hat, interesting, so it is so correct, which is where we're trying to go, it's called by main and main, so base 6040 codes are input, so I guess the first question is var 4 is the number of bytes if it's less than or equal to 12, which is what I want, okay, so it's just reading in 12 bytes, so if I label, so it could be basically if I provide the right 12 bytes, I think 12 bytes, well I'm always bad at estimating brute forcing, but I believe 12 bytes is a lot to get right to try to brute force that value, so if off calculating that value back on the stack, why is it to address a 14 plus C and then calculates md5, but that's not quite the right sub, off, the sub takes in this value and var C, which is the result of calculating the md5, which it outputs and then checks, so I need that var C to be that, or I need there to be some other buffer overflow or something to get me to redirect to that function, but there's canaries, so that's what I don't, I said there's canaries, but I don't actually see any canary checks, interesting, maybe there's canaries in some parts, I don't know, okay, eax, copy destination, calcd5, printf, the problem is I also don't want to look at this hash, because if I look at this hash, this will definitely probably give us the answer, which it's not really something I want to be doing right now, okay, this is how it compares it, I guess it's probably star comp is my guess, burn source destination, let's see this again, so mem copy, the number that gets passed in into this, but this var 14 plus C is so weird, why would you do that, I mean that would make sense of why this hash is always different every time, oh because of the ASLR, right, so this would make sense, because every time we run it, whatever it's hashing is some weird junk that we don't know what it is, var 4, okay, I want to look at the assembly here, so push up, move the stack pointer to the base pointer, subtract 28 hacks from there, move arg0 into eax, eax into esp plus 28, okay, so it's gotten rid of, it's not using ebp to reference variables, so argument n and then input, what the hell's input, oh that's that memory location of that 0804, whatever, whatever, interesting, okay, so that's the mem copy, so that load, oh no, no, that's the source, right, so we're gonna copy 12 bytes or C bytes, yeah 12, okay, so what if I do my Python, print, import, base 64, print, and I'm trying to do, I know, I know it's weird, I'm trying to do some Python C stuff, or Python 3, so I'm trying to use parentheses now, uh, base, there's a b64, encode, a times 0xc, it accepts up to 30 when it does the scanf, I wonder if that's important, just keep trying this line up to get that hash to match, ha ha, gb, okay, I've printed as a string, make it something like character pointer, yeah, okay, that makes sense, there's 12 bytes, okay, so move eax into, move ebb plus 8, which is the argument, which, or if I give it more real estate, it would show me eax is 12, which is exactly how many characters I sent, good, I wonder how it's doing that comparison, is there somebody to overflow it, probably not, but let's see, make some instruction, that eax, okay, so that's that fixed, that's input, yeah, okay, good, that's what's there, okay, so with input, I mean that's the base 64 decoded data, so it reads in 30 characters, which is 1e, so I think I could overwrite, I have no idea if this is going to be useful, 811, eb40, so I know I can read in 30 characters, oh and hex, but that's base 64 encoded, so I kind of like divided by 3 plus 2, is that c, which is exactly, but that's not true, I'm doing my math wrong, what if I wanted like ff, right, so yeah 20, so if I wanted 113, yeah, okay, and I think even 14 should be longer, well I know the equal signs of padding, so I guess I, yeah, as long as I can do that, that's 28, so what if I send that, it says wrong length, right, so it's not c, but I have overwritten some of these values in the input, is that correct, overwrite some of these values, is that useful, I have no idea, possibly, but not if I can't get to this function, which is a function I care about, okay, so this is the mcopy number, right, because this value, compare dword, let's see, okay I don't think I'd get past this length check, because it looks like, so I'm looking to see if maybe it compares, I don't know, the a l or a h, and maybe you could get it to go over, but that's, this is a dword comparison, okay, so even though we can scan in 30 characters into where, into var 22, which is 34, ESP, ESP, oh ESP plus 40 is EVP, interesting, so this just simplifies to EVP, so EVP minus 34, so it reads in 30, all right, so scan f, what's your semantics, the question is, okay, conversion, s, okay, that's a sequence of non-whitespace character, the next pointer must be a pointer to the initial element of a character A that's larger than 12, the input sequence and a terminating no byte, zero, which is automatically added, okay, so I can read 30 bytes, which doesn't really get me anything, I don't think, because I moved that value into var four, let's test this theory though, just to be 100% clear, I want the memory address, oh good, it says right here, I wish there was a good way to rename address, no, I don't want that, break star zero x, the 80493 start, authenticate, so now I want something that's exactly 30 bytes, okay, so right before we're going to call that, let's see, let's poke around a little bit in this program's memory, so we are there, and in x, oh the stack is this, okay, so this is evp3c, oh minus 60, okay, so this is the definition, definition, destination, is 18, is the destination, and so what does this look like, x, what about x, that's 20x, I want wide x, um, dollar sign evp minus, okay, so this value is going to x34, okay, there is just a pointer, huh, okay, okay, so are you guys on the stack, so the first argument is a pointer to the string, shoot, this means, oh good, var 40 is the source, so we're going to decode this, oh the scanf was the one I wanted to think about, okay, the scanf is var 22, right, right, right, right, vote effective address, yes, okay, var 22 is minus 34, that is okay, more interesting, here we go, think about do it just exactly, esp plus x40, oh this is a malloc, or a caloc probably, or memset, memset, yeah, number of bytes of value and location, okay, so this, I'm gonna guess is, okay, so this is calling, I'm guessing memset of 1e on, oh shit, it's not, it hexes in some places, okay, there we go, found it, wow, okay, string math, dude, okay, this is super confusing because we have decimal here and hex here, okay, great, so I've got that, so it's setting c characters of input, okay, then it's base 64 decoding that into there, and then when it verifies that whatever base 64 decodes into var plus minus four, j a is less than or equal to, so if I get base 64 decode to return a negative number, then that would work because that would be less than or equal to, could be interesting, I have no idea what, I feel like I already looked at this with this phoneable.kr stuff, this function, but no idea, let's see, so how's the control flow, if I calculate decode length, malloc variable c plus 1 into r1, and then open r1, blah, blah, okay, this does look like a custom function, var c calculated decode length, open ssl, stuff is nuts, it's the length, okay, it doesn't look like there's any way to get it to return a different length until less decode length can return me something weird, that's going to be useless there, calculate string length of the argument, so string length resolved, 0 into rc, move this into eax, calculate eax minus one into edx, subtract one from the result, it's supposed you could, okay, before you get too deep down this rabbit hole, what the heck, okay, so now I pass that check, I have c in there, let's see, push it, repeat, blah, blah, blah, move eax into, I'm sorry, move arg0 into eax, eax into var n, okay, so mem copy into the destination where the destination is, okay, var 14 plus c, weird, okay, next instruction, so that's pretty simple, take arg0, put it into eax, the next one is eax, yeah, ebp plus 8, and there's 28, okay, eax into esp plus 8, move input into the address of input into var 24, onto esp plus 4, so this is the source, and then put the destination, okay, so we take ebp minus 14, so that's 20 in binary, we add 4 to it, no, add c, add 12 to it, so that is 20, right, ebp minus 20, minus 20 plus 12, okay, it's just 8 plus x, okay, I want to look at eax and see what that is, okay, and then add in 12 to it, subtract, go down, let's go up, and move eax onto the stack, okay, back pointer, and what's ebp, ebp is a d1c8, c4, 8, b is still here, there's only eight characters, okay, so we have eight characters, so why the hell does it say that there's canaries and there's definitely not canaries in this function, that is weird, okay, definitely need to pivot, so we have eight and then another 4, which means we can overwrite save dbp on the stack, so that's a mem copy, so copy 12 bytes from the source which is the input global variable into the destination buffer, then calculate md5 on just what's in there, so call mem copy, okay, so we did that, now print me out the stack, yeah, 12 bytes, okay, 8 plus that in this, yeah, it's okay, so we just mess with ebp, great, so the last four bytes of whatever we send, get put into ebp, now we can start to do some fun stuff, but let's see what are the next things that happen, okay, so now we're going to calculate calculate calc md5 by moving c onto the stack, that's right there, and ebp minus 14 into eax, eax onto the stack, calculate md5, so then it's calculating the 12 bytes on the stack at d1b4, which is really, I mean x to the right of y to x, is really one, yeah, so this is this 12, which actually doesn't include, okay, four, four, four, right, so we took that value plus, it calculated at a far as 12, interesting, we're printing that md5 out, oh we just got to pivot the stack such that, okay, but then the aslr probably is going to mess things up, because this is definitely an address, it's getting hashed, I wonder if we need the hash, so it calls that, and then eax now has the strings attaching that value on the stack, okay, eax into ebp, blah blah blah blah blah, call printf to print out this hash, oh nice, I never saw this legend code heap stack string, ebp minus c onto the stack, that's a call stir comp, we're gonna do some stuff, it's gonna return 0, bt, up, oh string comparison using ssv42, yeah, no thanks, oh it can't go up the stack, I'll see you son of a bitch, well I know how to do that, or do I, okay, auth, turn it on here, take me to the end of auth, so I can control ebp 100% in this function, okay, so this leave, so the stack is, so the leave is gonna set up the stack and it's gonna change ebp, so now has 61, 61, 61, 61, the ret is gonna return here, so now auth is coming back, so now, okay, we only get four bytes though, so now it just compares eax with one, okay, if I can get it to get to correct, that would be good, I also have those other eight bytes, oh, okay, easy, maybe not easy, easy, but I get four bytes, okay, I know the location of where I wanna go, yes, okay, so I have 12 bytes, I have the last four bytes are gonna be ebp and, okay, this is good, so the value that we want is, our actual value that we send is gonna be copied into memory at a fixed location, which now means that can be our stack, so we can pivot our stack such that ebp points to there, which means when this function returns, which it compares eax with one, it's gonna jump as not equal, it's gonna move eax to zero, it's gonna do its own leave, and then it's gonna do a return, and it just got a seg fault, boom, so now if I get it to seg fault and jump to correct, then I'm gonna win the game, all right, this is actually pretty easy, so I just have to set this up correctly, I want to base 64 in code, all right, contact accept debug, p32n4 equals, this is where I want to return to, do a cool one, why not do it twice, plus, okay, so now I know this is going to be, so I want my base pointer to be pointing to the first one, which is gonna be an input, this address, p32, then let me bring up my bof exploit, yeah, now this is running at 9003b, oh, I have to conduct send line, import base64, base64.b in code, base64.b64 in code p, I think that may work, how lucky do we feel, I think pretty lucky, otherwise we'll run it with, got end of file, so that did not work, okay, I know I'm missing something, let's see, okay, so now I know this program pretty well, so let's, I want to break in auth, what I want to see, so I made some silly mistake, but I will find it soon, and I also want to make sure I get this payload, okay, so now x, 20y to x, address of input, so that address of input, I should have, yes, good, 08049, which is the address of correct, so now my ebp, I wonder how I get to re-display it, okay, my ebp points here, which means when I take my next extraction, so I just return back to main, now my base pointer points to here, so now I compare eax to 1, jump if not equal to 0, now I do a leave and return, which is going to, ah, pop ebp, right, right, right, so it's going to set the stack pointer equal to the current base pointer, and do a pop ebp, so this is actually going to set ebp to 08049, which is not what I want, so I was close, I just need to make sure my frame uh, my base pointer, here, okay, but that should be fine, right, where's the current stack, yeah, nobody cares about that, now if I do the next instruction, oh, okay, interesting, what's eax, eax is, okay, this, okay, so I did not make it that easy, we got super close, wow, this is a really well designed challenge, good job to whoever did this, so I jumped to correct, but remember correct, we forgot to check this dead beef of, of var c, of input, oh, it moves input, what is this, oh, it moves input onto there, okay, well, I could actually just jump almost maybe here and then call it, or try to figure out how to call it, but I see what they're trying to get me to do, they're trying to tell me that, hey, look, we want this first value to be dead beef, which is what it's doing, it's copying our, the input value onto var plus c, comparing it with dead beef, so if I make that be dead beef, I make that be there, and I do this plus four, plus four, so this will point to here, and that will be my, and now I think I should be good, no, so close, okay, oh, it does a pop ebp, right, right, this plus four is the wrong one, okay, right, it doesn't need that because it moves up to this next one, otherwise I was trying to jump here, okay, congratulations, we are good, oh man, oh, it took so much less time, I'm so happy, you have no idea, control ebp, control ESP, control the IEP, control the world, and that is great advice, and this is why Poneable.kr is one of the best Poneable challenges you can play, because honestly, that advice is correct, so this really does go to show how just by controlling ebp, you can now control the whole thing, so this was a super well-designed challenge, I really, like always, I always love playing Poneable.kr, I am very happy that this did not take me the whole time, like they talked about, it is definitely a simple login, again, I highly encourage you to do this on your own, it's good stuff, and I will talk to you all next time.