Thank you so much for these tutorials, I've been struggling analyzing and exploiting code for crackmes for awhile and this really gives a very detailed explanation of everything that is going on.
Is there anyway to tell beforehand where variables will be placed on the stack in relationship to each other by just looking at the code(2:06)? Why is the unsigned int ret located higher on the stack than buffer? On stack0 and stack1 the variable had to be placed after buffer[] in the code to be located higher on the stack. Shouldn't the ret variable be located lower on the stack than buffer[] ret is located after buffer[] in the code.
Kind of. But different compiler versions and different optimization levels might be different. They might rearrange. If you know how your compiler does it, you can know it beforehand
4:54 Why isn't the number after the SIGTRAP line 0xbfff7e0? Why is it 0xbfff7e1? Thanks in advance for your answer. Edit: I think it is because gdb breakpoint tells you the instruction it occurred at, but the int 3 instruction tells the instruction which is next, but i am not sure.
There is something I didn't understand. Why did you need this padding ("AAAA") after he returned to the system address? Why can't you just return to the system address and then just execute /bin/sh??
Normally, the caller (getpath) pushes the arguments it wishes to pass to the callee (address of "/bin/sh") first and then executes "call system", which is equivalent to pushing the return address followed by jumping to callee. Now the callee (system) expects its arguments to be placed right after the return address. Where "system" will return to after it finishes doesnt matter, but where it will find "bin/sh" does.
@@hahoangmanh2086I understand what he did. but in my case I replaced the system argument (in his case was the address of an environment variable) by a string of stack address content "/bin/sh" which I entered using the buffer. My buffer is `"A"* 80 + system + exit + 0x ???? + "/bin/sh" `.. 0x ???? is the address of "/bin/sh" in the buffer. I thought it did the same with re2libc, but it doesn't. Can you explain?
I was using the $SHELL environment variable for the system parameter and it did not work. Probably because, as you said, the stack is not reliable. To expand on that, I read the address of the shell environment variable in gdb. But when executing the program outside of gdb, the environment is different, so the stack addresses are shifted, therefore the address on the stack was pointing elsewhere. So then I watched your video and tried it with the static string address and it worked. Your videos are a gift to this world!
In the assembly we can see SUB esp, 0x68. Which is 104 bytes but if you look at the code their are only 64 (array) + 4(int) bytes allocated. Why does the assembly code show that actually 104 bytes are allocated on the stack and also we can see that we already get a seg fault by putting less than 104 bytes on the stack. What is happening here?
In both cases what worked for me was putting a second stack frame(0xbffff7c0+32)/system addres from libc together, like "print buffer+system_libc+system_lib+...", making a second call of the address in ESP, one after another, instead it I would receive the bzzzt or seg fault. Trying to understand why
On 7th stack, we just need to add a chain to first return to its own address because of its check for system call instruction. After that its all the same
We dont need to change the return address of system, but we need to put padding here to be able to put the address of "/bin/sh" in the libc just after. It's explained in the video you might have missed it ;)
Why can we only see the system function if the program is running? Why not while it's NOT running? EDIT: never mind. Must be because the libc library is dynamically linked. If it was statically linked I guess I could see it without having to run the program. These tutorials are SO AWSOME!!!!!! They make people learn much!!!! (At least if they choose to go deeper and understand everything they're doing like I'm trying to)
I also couldn't find a string in the gdb that is installed in the provided VM. It seems like that version contains a bug. With a newer version of gdb find works as expected. BTW, love your videos!
I understood everything. Except the part with return_after_system = "AAAA". Why do we need it? When I examined the stack without it, I could still see the address of /bin/sh next to the address of the 'system'. So why don't we get to our /bin/sh address if we don't write "AAAA"?
Well what I understood from my understand is that it should look like this --> System_fun_address + exit_function_address + argument_to_system_function_address --> After system function is done with execution, it returns back and goes to exit func and thus causes a normal exit of our vuln program. If you don't specify a address in between the system and its argument, there won't be an address for the program to get back to. Hope it helps.
This bothered me for a while as well - until I found this guide: www.shellblade.net/docs/ret2libc.pdf Pages 8 to 9 should clear this up (though it doesn't hurt to start from the top, it's a good read)
I'm trying something similar but on a x86_64 system and it happens that when the syscall from the libc_system is effectively called, the /bin/sh already starts as a zombie process, why am I getting this?
At 0x080484af, after gets in getpath has returned, the top of the stack has the padding for the integer, followed by the address of the ret of getpath. How does do those four bytes of padding get cleared off? I'm trying to follow the assembly and I can't figure out where $esp gets incremented somewhere before the first ret call leaving the ret at the top of the stack to be popped off...
the `leave` instruction is responsible for that. Like `ret` restors RIP to the value on the stack, `leave` restores the old ESP (which is EBP). `leave` performs a `mov esp, ebp`, so this is where it gets "cleared"
in a video about ret2libc the chap talks about the command 0x80484a0 being put on the top of the stack, from the assembly it looks like it's just putting that address of the command in ESP (the register) not on top of the stack? shouldn't it be "put 0x80484a0"
somehow I find it strange: you return to the address of the "ret instruction", which is not even in the stack, isn't it a seg fault? And it seems contradictory that the "ret" should pop an adress and return to that address( on the stack ) , but in your video, it seems like the "ret" just pop the "0x080484f9" and move to the next address on the stack. Shoudn't it return to "0x080484f9"?
he overwrote the EIP register with a buffer overflow, then set the top most value on the stack to be that specific address, and when it reached *ret*, it popped eip to the same specific address and returned again at *ret* and since it popped the top of the stack the next address is 0xbff..etc yea top of the stack is wrong cause it grows to 0 so yea, ik dont correct me
When the EIP reaches the address of system, it will call system and the command will be exactly after the return address. So why did you send "system + return_after_address + bin_sh" and not "system + bin_sh + ..." ?
this is mentioned in another comment, and quickly explained in the video, but when system is called, the value on top of the stack should be the address that will be returned to after system is finished, and the first argument for system (the address of the "/bin/sh" string) is immediately following. if the call to system ever finished (you exit the shell), the program would then try to return to the address 0x41414141 (AAAA)
Not that much coincidence. The base address is always fixed without ASLR. And both programs are super short and thus likely the stack address is very similar, if not even the same ;) Good catch!
LiveOverflow thanks for getting back to me. I used the gdb-foo you’ve shown in previous videos and also proved this point for myself. Can’t thank you enough for these videos - a high quality resource on the subject.
You probably figured it out, but maybe others are asking the same question. He found it in gdb by setting a breakpoint on main, run and then check the mappings on memory with "info proc mappings". The addresses are not changing in the protostar virtual machine, because ASLR is disabled. So all of the addresses are static in that case.
keep in mind that the stack might change but yes after we fill it , we try to return and hit with the adress in nops(which are follwed by the shellcode)
Adding multiples of 16 to hexadecimal numbers is "nice" and easy to see what the resultant address would be. Think of it as adding 100 to 543, you can immediately see the result is 643, compared to say, adding 86. Though any other similarly sized number will be fine and do the job.
hello , i tried to comment your post on reddit but i coudn't , my question is for the first part , you showed that we can't return to the stack where we could put our shellcode , because of the function that test our return @ (__built....) , but when you explained how to return to another function we return to the stack too !!!! so the if statement will be true !!! , i don't find a meaning for you first solution because we will normally get bzzzt too.
The test only happens once on the return. So the first return address passes the test. The test is over. Now we simply chain another return to it and can happily return into the stack. Also it doesn't matter at all if you find meaning in it or not. An exploit is proof by construction. It works because it works. Step through it if you don't believe it.
I leave this comment to prove that during my life, i've watched this video "Doing ret2libc with a Buffer Overflow because of restricted return pointer - bin 0x0F" and i've done this level
OMG i am so noob i try override main's stack with shellcode , in gdb works but out of gdb does not work :( , literally i try this 5h, thx for the video :CCCCCC
yeah but he says that stack space is not enough and second and more serious matter is: this technique is used to bypass the no-stack-exec he just shows simple example before!
Although it is only about 10 minutes video, you brought me a huge of background information. Really appreciate!!
Thank you so much for these tutorials, I've been struggling analyzing and exploiting code for crackmes for awhile and this really gives a very detailed explanation of everything that is going on.
I just found out that instead of running `r < script_output` in gdb, you can run `r <
I tried that but it didn't work for some reason, for me the following worked:
r < `python /tmp/script.py`
@@MichalMonday better is r $(cat payload)
"now that you are almost a pro at exploitation" YAY
Is there anyway to tell beforehand where variables will be placed on the stack in relationship to each other by just looking at the code(2:06)?
Why is the unsigned int ret located higher on the stack than buffer? On stack0 and stack1 the variable had to be placed after buffer[] in the code to be located higher on the stack. Shouldn't the ret variable be located lower on the stack than buffer[] ret is located after buffer[] in the code.
Kind of. But different compiler versions and different optimization levels might be different. They might rearrange. If you know how your compiler does it, you can know it beforehand
thank you for the vids, they are very informative and fun!
also i love the way you say "breakpoint" :D
4:54 Why isn't the number after the SIGTRAP line 0xbfff7e0? Why is it 0xbfff7e1? Thanks in advance for your answer.
Edit: I think it is because gdb breakpoint tells you the instruction it occurred at, but the int 3 instruction tells the instruction which is next, but i am not sure.
Man why TF your videos are soo underrated. The real hacking lies here!!!
There is something I didn't understand.
Why did you need this padding ("AAAA") after he returned to the system address?
Why can't you just return to the system address and then just execute /bin/sh??
Normally, the caller (getpath) pushes the arguments it wishes to pass to the callee (address of "/bin/sh") first and then executes "call system", which is equivalent to pushing the return address followed by jumping to callee. Now the callee (system) expects its arguments to be placed right after the return address. Where "system" will return to after it finishes doesnt matter, but where it will find "bin/sh" does.
@@hahoangmanh2086 Thanks. Your explanation help me clear my head after an hour staring to the screen :))
@@hahoangmanh2086 Well explained
@@hahoangmanh2086I understand what he did. but in my case I replaced the system argument (in
his case was the address of an environment variable) by a string of stack address content "/bin/sh" which I entered using the buffer. My buffer is `"A"* 80 + system + exit + 0x ???? + "/bin/sh" `.. 0x ???? is the address of "/bin/sh" in the buffer. I thought it did the same with re2libc, but it doesn't. Can you explain?
I was using the $SHELL environment variable for the system parameter and it did not work. Probably because, as you said, the stack is not reliable. To expand on that, I read the address of the shell environment variable in gdb. But when executing the program outside of gdb, the environment is different, so the stack addresses are shifted, therefore the address on the stack was pointing elsewhere.
So then I watched your video and tried it with the static string address and it worked. Your videos are a gift to this world!
In the assembly we can see SUB esp, 0x68. Which is 104 bytes but if you look at the code their are only 64 (array) + 4(int) bytes allocated. Why does the assembly code show that actually 104 bytes are allocated on the stack and also we can see that we already get a seg fault by putting less than 104 bytes on the stack. What is happening here?
I believe these videos can be considered legitimately good don't know why there are so few likes.
I know this is an old video, but I cant figure out how did you find the address 0xb7ecffb0 at 8:53.
Oh, I have rewatched the video again, and it's shown when you type p system in gdb. You can see that at 7:26.
In both cases what worked for me was putting a second stack frame(0xbffff7c0+32)/system addres from libc together, like "print buffer+system_libc+system_lib+...", making a second call of the address in ESP, one after another, instead it I would receive the bzzzt or seg fault. Trying to understand why
On 7th stack, we just need to add a chain to first return to its own address because of its check for system call instruction. After that its all the same
Hello sir I have a question
Why we change the return address of system function and how system will take /bin/sh as input.
We dont need to change the return address of system, but we need to put padding here to be able to put the address of "/bin/sh" in the libc just after. It's explained in the video you might have missed it ;)
Can you make a video about the main differences about the gef and the positive and negative points of the ped?
can radare2 replace gdb with peda?
Why can we only see the system function if the program is running? Why not while it's NOT running?
EDIT: never mind. Must be because the libc library is dynamically linked. If it was statically linked I guess I could see it without having to run the program. These tutorials are SO AWSOME!!!!!! They make people learn much!!!! (At least if they choose to go deeper and understand everything they're doing like I'm trying to)
I also couldn't find a string in the gdb that is installed in the provided VM. It seems like that version contains a bug. With a newer version of gdb find works as expected.
BTW, love your videos!
thanks for the explanation
if you used the int3 syntax i would imagine might influence the handler for the syscall since system call wiould have a different interrupt.
I understood everything. Except the part with return_after_system = "AAAA". Why do we need it? When I examined the stack without it, I could still see the address of /bin/sh next to the address of the 'system'. So why don't we get to our /bin/sh address if we don't write "AAAA"?
Did you find out why the "AAAA" is needed in the exploit? I am still struggling to understand this part of the exploit.
Well what I understood from my understand is that it should look like this --> System_fun_address + exit_function_address + argument_to_system_function_address --> After system function is done with execution, it returns back and goes to exit func and thus causes a normal exit of our vuln program. If you don't specify a address in between the system and its argument, there won't be an address for the program to get back to. Hope it helps.
it's just that we don't care where the function system returns to because it will return to there only after the execution of the program is done
This bothered me for a while as well - until I found this guide: www.shellblade.net/docs/ret2libc.pdf
Pages 8 to 9 should clear this up (though it doesn't hurt to start from the top, it's a good read)
Thanks. The best resource to get started on the topic.
I'm trying something similar but on a x86_64 system and it happens that when the syscall from the libc_system is effectively called, the /bin/sh already starts as a zombie process, why am I getting this?
At 0x080484af, after gets in getpath has returned, the top of the stack has the padding for the integer, followed by the address of the ret of getpath. How does do those four bytes of padding get cleared off? I'm trying to follow the assembly and I can't figure out where $esp gets incremented somewhere before the first ret call leaving the ret at the top of the stack to be popped off...
the `leave` instruction is responsible for that. Like `ret` restors RIP to the value on the stack, `leave` restores the old ESP (which is EBP). `leave` performs a `mov esp, ebp`, so this is where it gets "cleared"
Aaaaahhh! Of course! Thanks!!
in a video about ret2libc the chap talks about the command 0x80484a0 being put on the top of the stack, from the assembly it looks like it's just putting that address of the command in ESP (the register) not on top of the stack? shouldn't it be "put 0x80484a0"
it is just me or not ? after returning to ret adress of getpath and continuing to 0xcccccc, i get a seg fault at the adress 0xcccccc. What's wrong ?
somehow I find it strange: you return to the address of the "ret instruction", which is not even in the stack, isn't it a seg fault? And it seems contradictory that the "ret" should pop an adress and return to that address( on the stack ) , but in your video, it seems like the "ret" just pop the "0x080484f9" and move to the next address on the stack. Shoudn't it return to "0x080484f9"?
he overwrote the EIP register with a buffer overflow, then set the top most value on the stack to be that specific address, and when it reached *ret*, it popped eip to the same specific address and returned again at *ret* and since it popped the top of the stack the next address is 0xbff..etc
yea top of the stack is wrong cause it grows to 0 so yea, ik dont correct me
Can u plz make a video on ret2libc 64 bit???
When the EIP reaches the address of system, it will call system and the command will be exactly after the return address.
So why did you send "system + return_after_address + bin_sh" and not "system + bin_sh + ..." ?
this is mentioned in another comment, and quickly explained in the video, but when system is called, the value on top of the stack should be the address that will be returned to after system is finished, and the first argument for system (the address of the "/bin/sh" string) is immediately following. if the call to system ever finished (you exit the shell), the program would then try to return to the address 0x41414141 (AAAA)
It’s just coincidence that the eip from the previous challenge happened to also put us in our nop slide here too right?
Not that much coincidence. The base address is always fixed without ASLR. And both programs are super short and thus likely the stack address is very similar, if not even the same ;)
Good catch!
LiveOverflow thanks for getting back to me. I used the gdb-foo you’ve shown in previous videos and also proved this point for myself. Can’t thank you enough for these videos - a high quality resource on the subject.
@liveoverflow how can I learn Assembly language for buffer overflow and for reverse engineering?
How did you find the address that libc is loaded into? Wouldn't change for every run?
You probably figured it out, but maybe others are asking the same question. He found it in gdb by setting a breakpoint on main, run and then check the mappings on memory with "info proc mappings". The addresses are not changing in the protostar virtual machine, because ASLR is disabled. So all of the addresses are static in that case.
@@f41nT Yes I am much more experienced now, but thanks for the explanation anyway, will might help other people.
How did you get the address 0xbffff7c0 in eip = struct.pack("I", 0xbffff7c0+32) ?
And why +32?
,,why +32?" there is no reason , u can try with 20 ,25,40...dont matter it will work
keep in mind that the stack might change but yes after we fill it , we try to return and hit with the adress in nops(which are follwed by the shellcode)
Adding multiples of 16 to hexadecimal numbers is "nice" and easy to see what the resultant address would be. Think of it as adding 100 to 543, you can immediately see the result is 643, compared to say, adding 86. Though any other similarly sized number will be fine and do the job.
whats the point of using return after system variable?
How do the adress of bin/sh changes from 0x08048a0 to other
Hey, when I run the script with the addresses, I keep getting "segmentation fault" (python stack6; cat) | /opt/protostar/bin/stack6
run this in gdb to see the value of eip before causing seg fault
@@nivmoshe5536 It happened with me as well, gdb works like a charm but running this in the normal shell gives a SEG fault
hello , i tried to comment your post on reddit but i coudn't , my question is for the first part , you showed that we can't return to the stack where we could put our shellcode , because of the function that test our return @ (__built....) , but when you explained how to return to another function we return to the stack too !!!! so the if statement will be true !!! , i don't find a meaning for you first solution because we will normally get bzzzt too.
The test only happens once on the return. So the first return address passes the test. The test is over. Now we simply chain another return to it and can happily return into the stack.
Also it doesn't matter at all if you find meaning in it or not. An exploit is proof by construction. It works because it works. Step through it if you don't believe it.
it took me 2 days to understand this 0_0
I leave this comment to prove that during my life, i've watched this video "Doing ret2libc with a Buffer Overflow because of restricted return pointer - bin 0x0F" and i've done this level
Well played
Yes
@@thecrazzxz3383 bro you talking to yourself?
@@finesseandstyle Of course ! Don't you do it as well ?
@@thecrazzxz3383 sure but i don't leave comments after every 3 months or smth like bruh xD
hello , can you please add the wbsite you use as a description on the video ,thanks.
I have a question: if I don't know the libc version, what can I do to discover that?
that’s not an easy problem
needs leak and guessing
@@davidhcefx Thank you sir
Tanks this video is excellent
Does anyone knows with gdb do that weird search thing?
does this bypass ASLR?
OMG i am so noob i try override main's stack with shellcode , in gdb works but out of gdb does not work :( , literally i try this 5h, thx for the video :CCCCCC
there’s a thing called ASLR, which would be disabled inside gdb
if you can put a \xCC in the stack and execute it, you could just put in your normal shellcode again and get a shell that way, couldn't you_
yeah but he says that stack space is not enough and second and more serious matter is: this technique is used to bypass the no-stack-exec he just shows simple example before!
Mach mal bitte deutsche Videos! (Am besten von der Binary Hacking Serie)
sorry, dafür hab ich keine Zeit. Einfach englisch lernen ;)
@@LiveOverflow Ich versuchs^^
要是有中文字幕那就太好了