 Hey, folks, Adam B. Pay here. And today we're going to be looking at the Poneable.kr challenge ASM for assembly. So this is a six point challenge. The thing says, mommy, I think I know how to make shell codes. So this should be a shell coding challenge. Should be super fun. SSH into that machine. So when we go onto that machine, we have ASM, ASM.C, and a read me and says this is the Poneable.kr flag. Please read this file. Why is that? Oh, good. Interesting. OK, this is fake flag file for letting you the name of flag file. So OK, we have the assembly. Ah, the read me. Great. OK, once you connect to port 9026, the ASM binary of executed under ASM Pone privilege may connect into the challenge, then get the flag. Flag name of the file is the same as the one in this directory. So we will need to connect to this port and be able to read this file. So we get this binary. So we can run it first. Welcome to shell coding practice channel this challenge. You can run your x64 shell code under seccomp sandbox. Try to make shell code that spits flag using open, read, and write syscalls only. This does not challenge you. You should play ASG challenge. Give me your shell code. Let's say this is my shell code. Suck fall. OK. So this actually makes a lot of sense. So main sets these buffers. This is so that it doesn't do any buffering so that that way when you're talking to this on the network, all the traffic is sent back to it. So calls sh does mmap. Mapping on this Mac fixed private memset sh. So I could look at these instructions. Mem copy stub offset size of stub. Give me your x86 shell code. Read into sh plus offset 1,000 bytes. Alarm 10. That means basically trigger an alarm so you have 10 seconds to do this. You're in a secret jail. You can't use symlink in slash temp. Home, ASM, Pone. Sandbox. And then jump to sh. Interesting. OK. So sandbox is running, doing a set comp filter. So set comp is a security mechanism in Linux that's used to restrict the system calls that a program and a process can make. So the idea is it's adding rules to allow us to call open read write exit and exit group. So basically what they're challenging us to do is most shell coding calls slash bin slash sh in order to get a file. So sorry, in order to own a process. So what they're saying is we're actually, we'll let you execute whatever code you want, but you can only call open read write and exit. And so once it's done that, then we should be able to do this. So basically we know that our code will go after stub. So an important thing will be to maybe look at what this stub does, then we'll write some assembly code to read the file and call open. Yeah, this will be an interesting challenge. I'm actually pretty excited about this. One trick is we need to, we know we need to keep it within 1,000 bytes, so that's as much as we have, but beyond that, I think we're in pretty good shape here. So let's see, can I, what do I want to do? Let's open this up in Hopper. I just want to see what this stub code is, because that will actually, that way we'll know exactly what our code is. Okay, asm, asm, yes, it is an elf. All right, give me your shell code. So let's see, there should be this stub. So where's stub used? It's passing a string length, they're size of. There you go, stub. Okay, so what I can do is I can tell Hopper, hey, all this stuff is actually code. Okay, so we can look at this. It's basically a super easy code. It's essentially clearing all the registers for us. So no rax, rbx, rcx, rdx, rsi, all these registers are all completely, s. Okay, so this is what we need to do. We need to write shell code. So we can't rely on any values being in any registers. We really can't rely on anything. So we can only have x80, sorry, x64, this is a 64-bit shell coding challenge. Awesome, okay, cool. So what we're going to do, and see, I'll probably need to look at a primer x64 basic assembly. That should be 64. I just need the, so what we'll need is we'll need what the basic assembly looks like, like how to write an assembly file that GCC will be able to compile. We'll also use shellnube, which is done by my friend, Yannick Fred Antonio, or Rammer. See if I have that, no, I do not. So, which basically is super cool, and gets, yeah, so install, okay, cool. Yeah, so which will allow us to actually take in the assembly file and output exactly what we want is the bytes that we need. So, let's look at this. So we need introduction. We need the x64 syscall convention Linux. So we need to know how to make these syscalls in 64. System called table. There we go. There we go. x864 Linux system call convention, refer to section system five. Yeah, there we go. UseLand's application used as indiregisters for passing sequence, RDI, RSI, RDX, RCX, R8, R9 to call assist call. Okay, so what are we gonna wanna do? So when we think about our code, we will want to call essentially open. So we need to look at man to open because we wanna call the open syscall. So we need path name and flags. So we need to call open path name. We actually know exactly what the filename is that we want to read. This is, yeah. Okay, so I'm gonna essentially put this in a comment. That's not how you comment. That should be how you comment. And then the flags that we look for. So flags, basically we want, we just want a read, create, direct, sync, excel. Must include one. Read only. We'll need to actually also see what that value is, right? It's because we, so this is essentially what we wanna call. So this is gonna be something like int fd is equal to that because we know from this man page that it will return an integer which is the file descriptor. Then, so we can call open seccomp. Yeah. So we can call read. Count is zero, read may detect this. The reason it's not check variables. Okay, so then we wanna call. So yeah, the important thing is we know exactly what we wanna do. Then we wanna call read into file descriptor fd into some buffer. So now we actually need a place of where to put this. So we can use redel-s. So we're gonna look at all of the sections here and see where, because we need a writable section because we don't wanna overwrite one of the other sections. So we can, yeah, .data. So we'll use .data. So that's at, ooh, I wonder if this is going to be interesting. Interesting. I guess I never end check sec on this. So NX, PIE. I think this should be in the same location. So I'm gonna assume this is fixed for now. So I basically want to read into that buffer all of the file. And I don't know how much there is. So let's say, I don't know, a very large number. So when we call this, the operating system will read bytes from the file into that buffer. And then I want to write. And now I want to, man, to write. So these are the function calls that I can do right into the file descriptor. So this is where it goes back to that punnable.kr challenge of file descriptors. So standard input, standard output, standard error. So I know my standard output is coming back to me. So read, write to standard output, this buffer. And that many bytes. So that's essentially what I want to write. So now I have some examples somewhere, but I don't, GCC sample program. My keyboard's not working. There we go. Aha. Yes, I knew there was a dot glow, okay. All right, so now here we go. Now we can, so I know I want to call open. I'm going to call move. Let's see. Move, dollar sign one, no, that's right. So I'll need the list of system calls. So open is two. So move dollar sign two into rax, then move. So now I need the arguments. So I move two into rax. So rax is going to be open, the file name rdi. So this is a little bit trickier, is I'll need to, let's see, and I don't, we just reached into here and we saw that I actually don't have, where are those values? Yeah, so I don't have a base pointer. I don't have, I do have a stack pointer, that's good. Okay. So I don't have any of these registers. So if we were doing this as a normal program, we could just say, well, move just like this example here. Move, let's say, dollar sign message into rdi. And here, dollar sign fn, so file name into there. And then I'll have here, so fn.asky, this is this big thing, all right? And so that will know that that, to move that into there, we'll actually see that this will not work, but we'll be able to deal with that. All right, flags into rsi. So what is the value of, all right? So we need the actual value in there, right? Because we, zero, open for reading. I mean, we can, we have the bytes, we actually know that it's already zero, but let's just set this up properly just to make sure. So I need to move syscall table, move zero, into rsi. All right, and so what that's gonna do is that will then put the return value. So based on the, the number of the system call, upon returning the register rax. So rax now has the file descriptor number. So, so now that should essentially be this. And now I need to move from rax into, let's say rbx, that will store the file descriptor. So now I can move the actual percent. So it should be a percent. All right, so now I can move based on my syscall table here. So now I wanna call read. So sysread is zero into rax. And then move this value into rdi. And move the number of bytes I wanna read, which I really don't know what it is offhand. So I'm, we want, just wanna read a ton of bytes into r, ah, I have this backwards, okay. So our si is the buffer, the size is rdx. And the file descriptor that we want to read from rbx into rdi. So that will return the number of bytes that were read, but honestly we don't really care as long as they get written out properly. So now we wanna call write. So we don't need the return value. So now we just need to call write. So we need to move dollar sign one into rax. Move the file descriptor. So we wanna write into one rdi. And then we want to the buffer into rsi. So these will be the same. Actually, now we know how many bytes. So we can actually say move rax, which is the return value of the read command into percent rcx. And so instead of moving that into rdx, we can move percent rcx into rdx. Okay, the other thing we need to make sure is none of the registers we're gonna use get clobbered. This clobbers rcx and rdx, r11 as well as rax, but other registers are preserved. Okay, so rcx should be fine. We don't depend on that path to syscall. I didn't call syscall here. That would be a problem. And that should be fine. And we can call and exit if we really wanted to. Yeah, I mean, might as well. That's nice. So dollar sign 60 into percent rax. And move percent zero into more sign rdi. Okay, so this should be good. And we can actually test that this, we can compile this. So it's not gonna work A because we don't have this file. So we can actually try it with that. But let's just see that we can actually execute this in function main, notify address into rbx. So let's see what do we do? We call open. It actually is, weird why is there no zero there? Maybe I need to null byte out that. See the .asky. Zero read only, bad file descriptor, bad address. Okay, so let's actually, we can test this. Let's, so it's still not reading that file correctly. I wonder why that is. Clearly I messed up something in this .asky. Oh, so I don't actually have anything at that memory address. So I can't read and write to it. Two zero, two zero, A zero. Yeah, that's funny. Okay, so, okay. But the problem is in, I can actually show this very quickly. Oh, sorry. So the problem is, so we're looking at this code, move two into rax, move this value into rdi. And remember, this is the file name that we wanna open. So the problem is, I know that this memory location should exist in the program because of the, because this should be where the byte is. But the problem where the .data segment is, the problem is that doesn't exist in this program at all. We don't have that section. So, it's not working, but it is working and it's calling all the system calls we want. But we can't actually use this because this memory location is not going to exist at that point in time. So if we look at main, this 400537, we need these bytes, this underscore. So what we need to do is get that data somewhere that we actually know in memory. So how big actually is this? I just wanna figure out the length of this string, 231. Okay, so some of the things, tricks we can do. So we just need to get this value somewhere. So I can't use move fn to percent rdi. So I need these 231 bytes to be in memory. And I need a pointer to them. So what I can do, so a couple of things I could do, I could actually use the stack, which I think will work. So I know I have a stack. So what I can do is first, so I'll need that into rdi. So let's move $rsp into rdi. So that's the current location of the stack. And I'm going to just push, let's see, and I could do this 64 bytes at a time. Is that right? So the question is, which order do I want to do this in? And let's see, okay, so let's see. Okay, and now, so now when I come back to this, compile this, I should see operand type mismatch for push. Let's see, x64 push. So essentially, I just want to copy constant values onto the stack by pushing them onto there. Question is, why isn't this working? Maybe I need to push q, line eight. So type mismatch on line eight. This would be line eight, push. Trying to push a pop, so you should play with the stack. All right, we want to push a constant value onto the stack. Oh, apparently it'll only do 32, okay. So that's nice, cut that in half. Let's see, that did not work correctly of what I wanted to do. That's the current stack pointer onto there. So let's GDP this run. All right, so rsp is at a certain place. So move that onto there, push that onto the stack, push zero onto the stack, it's there, 70. Right, so rdi is actually, okay, 78, I see, right. Okay, so pushing, so I'm gonna push, okay, so I need to push it basically in reverse order. Is that right? So I wanna first push zero, and then I'm gonna end up pushing, let's say, and the other thing is it needs to be divisible into one, two, three, four, divisible by four. What did I say the length of this was, 232. Okay, so that's what I want to do, and then I want to basically turn this into hex. All right, so this is, gives me almost what I want. So I need these bytes in the reverse order of what I want them in. But let's, so let's say like I just wanna open the file, let's say a, atom, so there we go, 61. So let's say put this, so m is gonna be 60, a is 61, d is gonna be 64, a is gonna be 61. So now, okay, now if I, now I'm opening the file, atom. So I just need to push it onto the stack in reverse order, and this should work. Okay, so I can easily write a, okay. What I need here is, wait for, okay, reverse the bytes. It's actually fine if I can just get, that's annoying not having it like that, okay. Well, then make annoying things easy here, up this and there. Yes, I do know I could definitely write a Python script to do all this, and to translate this for me, but you know what, I like using my Emacs macros. Oh, I didn't reverse it, that makes sense because, I mean, I guess I could actually go in reverse order, but it'll make more sense to my brain to go this way. And let's get this guy, get that thing. All right, so these are the bytes that I want, and so I'll write a macro to do it basically four at a time and to write the push instruction. So push, touch on zero x, three, four, there, there. Start up in here and the macro, and that big string in there, almost done. Wait, y, six, seven, six, e, b, f, three, six, six, f, 30, six, f, 30s. Yeah, but why did that end up at the end like that? Let's try killing it and just starting over, because I feel like that should have worked. Okay, let's look here. One, two, three, four, one, two, three, four, yeah. That's a lot of garbage here. Three, four, one, two, three, four, one, two, three, four, four, four, four, four, four, four, four, four, four. All right, for whatever reason. So I know that that's a slash, two f, so two f. So dot, slash, slash, slash, slash, which doesn't do anything. Okay, but we absolutely need to test this locally because otherwise there's a good chance this just breaks. Dot, slash, slash, slash, slash, slash, slash. Yeah, but why didn't it continue? Okay. Oh, weird, each push is only doing four bites. Okay. Okay, so the way I will fix this is, so I will need to, how do I push immediate? Man, that's super annoying, how come that? Yeah, there we go. There is no push media, it's work around. Yeah, okay, so I'm gonna have to go through a register, that makes sense. So I'll need to change all of this. So close, so close. This is why you test things. Okay, but the question is, how do I, so what's the length here? Should work, so first push zero, so we know we have zero at the very end. And what do I want to do? I want to move, okay, so I'm gonna move that into Rax, it doesn't really matter, and then push Rax. So I want to move, oh, I first want to, okay. Move, and immediate value, 87. Eight, now I need to make sure this is exactly right. So let's count, one, two, three, four, five, six, seven, eight. Good, okay, move that on there. And now I want to, oh, actually, into Rax. And then do a push dollar sign Rax. Make it there, make it here, go back up here, close it. And actually what I want to do is to make sure that this actually works before I run this macro and start spending all this time on this. Let's GCC this, let's GDP, so we should see Oolong. And that should be the very end of the string. We can see what's going on here. I basically need a bunch more of these push dollar sign Rax. All right, nope, let's GCC it first. Oh good, okay, so it was able to get it, read it, and write it, awesome, all right. So now that works, now we can use, let's get install shellnube, right, getting shellnube. I just want to install this so I can use it. All right, snube, snube.64. So super cool, basically this allows you to, I can compile, so I can basically say that, hey, from ASM, from assembly shellcode.s dash dash two, and there's a lot of different awesome modes here about what it can output as. So the output format, assembly, object, and executable of binary hex, two, let's say hex, no code, hex, okay, that's not exactly what I want, but let's do two pythons, okay. So here's the output that I need to send, and so now, let's see, oh actually you know what, I want to bin. So now this binary is, this should be the assembly version of all of that, and so am I within a thousand bytes? I guess that's the key question. Oh, and you know what, I included in here this string, so I'm going to get rid of this because I do not need this anywhere. Now let's do that to bin much less, I believe. All right, so I gotta make sure I'm within the 1A0, is that less than a thousand? Yep, much less. So I am going to scp, so let's make a temp at md, because I need to actually send this binary, this shellcode there, so I want to scp, I'm already doing it. All right, cat shellcode.c, nc0, 90, 26. So why did that not work? Give me your x64 shellcode. Okay, so we can just write in, so we'll just write in that little exploit using PwnTools, be localhost, d26connection. Let's see, I want read until, the problem is you do this so much you don't remember all the exploits you have. Ah yes, receive until, what is this? Give me your x64 shellcode. Then we send, so now I have it in, so this should be my payload. So I should be able to send that and then turn the connection into interactive and we'll see what happens. So this file in here, why does that not work? Okay, well let's GDP it locally. Let's see, breakpoint in hopper. Let's see, I want to just start main. Yeah, okay, so read, so that should be fine. So read, let's break here. I see, I think one of the problem is the buffer. We're not gonna be able to have a good buffer. So let's, there we go, this is where I want to break. Okay, continue there. Okay, call read, so jump over that call. So now, so read 1A9 which is nice. And so I can actually verify that it, so I know that let's say this read call is passing in, read the file descriptor, the buffer into RSI, so RSI. What I can do is I can say X, I can look at this and say, okay, yep. So here's my push zero, my move into RAX, push RAX, my this, syscall, there we go. Okay, great. And then I can do next instruction, call the alarm function, load effective address, CH root, which is not gonna work, but that's fine. Call the sandbox, move that into there. Okay, so now set up instruction. So now call RAX, so now XOR, so this is remember that part at the beginning, XORing all the registers out, eight, nine, 10, 11, 12, 13, 14, and 15. So all we have is a stack pointer and a, so now push zero onto the stack, push, and then push that, this and then that, and this and then that, and this and then that, and this and then that, continue doing this while until you have this stupidly long thing. Yes, this file name is very long file. Please read this file. Sorry, the file name is so long. Okay, boom, and push that dot slash slash slash dot. This is portable dot care flag. Please read. Okay, RAX, two to RAX, move zero into RSI, syscall. So now RAX is three, good, that works. Okay, so I think I see the problem. The problem is that, so this is not gonna work because this buffer, so I think the fact that this is a PIE executable means that the data segment is going to be somewhere completely different every time, so we're not gonna have a 20, a 20, a zero. Yeah, I cannot access that memory address. Okay, so I can't rely on that memory address, but I do know of a region in memory that is writable. You may have heard of this memory region before. It is called the stack, and so we just use the stack to get this name, but we only need the name after we call the read instruction. So this is good, so now we can do this. Move that there, syscall. So now what I need to do, so at this point, and move the stack pointer into RDI, so now what can I do? Well, RDI will persist, so basically, cool. So basically what I want is, I'm gonna want, basically I know the stack pointer at this point, and I'll just use this stack. So read, instead of this, EX, what's RBX? Oh, that's the return value. That's gonna be the return values in there, but first, let's move RDI into RDI, EX, so move the stack pointer, the file name, into RSI, the RSI should still have the same thing. All right, let's go back, let's show new bit up. I could just remember where I did this, probably this one. To Python, to bin, strace, a.out, so I wanna make sure that, oh, there we go, great. Read in three from there, testing, output testing, okay. I think this should work. So let's say, give me it to ESM, there we go, testing, all right. So I think this should work, so now we can, there we go, making shell code is very easy. All right, that took a little bit longer than I thought, but it was super fun, log in first, see if it needs to take you longer than it takes to log in, that's a bad sign. So it took me a little bit of time, mainly because I'm much more familiar with 32-bit shell coding and 32-bit assembly, but here we go, got this flag, got six points, better than nothing, great. So look at this, this is awesome. So we have one more challenge left in the ponible.kr, the toddlers battle, and then we can move on to rookies. So thanks for watching and see you next time.