Blast from the past, Part 13:
Incase you missed Part 13, check out the link above, sequence matters here
Stack Protections:
A Canary is a certain value put on the stack (memory where function local variables are also stored) and validated before that function is left again. Leaving a function means that the “previous” address (i.e. the location in the application right before the function was called) is retrieved from this stack and jumped to. If the canary value is not correct, then the stack might have been overwritten / corrupted (for instance by writing more stuff in the local variable than allowed – called buffer overflow) so the application is immediately stopped.
In this case when we checked the security permission it is like:
The stack is not executable, so we can’t just place shellcode in it and expect it to run.
DISAS, the kickass way :
Next step is to disassemble main
.
Breakpoint 1, 0x08048257 in main ()
gdb-peda$ disas
Dump of assembler code for function main:
0x08048254 <+0>: push ebp
0x08048255 <+1>: mov ebp,esp
=> 0x08048257 <+3>: and esp,0xfffffff0
0x0804825a <+6>: sub esp,0x30
0x0804825d <+9>: mov DWORD PTR [esp],0x80ab668
0x08048264 <+16>: call 0x8048f40 <puts>
0x08048269 <+21>: mov DWORD PTR [esp],0x80ab680
0x08048270 <+28>: call 0x8048d80 <printf>
0x08048275 <+33>: lea eax,[esp+0x10]
0x08048279 <+37>: mov DWORD PTR [esp],eax
0x0804827c <+40>: call 0x8048db0 <gets>
0x08048281 <+45>: lea eax,[esp+0x10]
0x08048285 <+49>: mov DWORD PTR [esp+0x4],eax
0x08048289 <+53>: mov DWORD PTR [esp],0x80ab698
0x08048290 <+60>: call 0x8048d80 <printf>
0x08048295 <+65>: mov eax,0x0
0x0804829a <+70>: leave
0x0804829b <+71>: ret
End of assembler dump.
This gives the registers and all the instruction calls.
This is the key:
gets
cannot be used securely, since it doesn’t do any bounds checking. We can override the return address by providing input of the correct length, which is 48 bytes in this case. The last 4 bytes will overwrite the saved EIP.
The idea to is to spawn a shell, so let’s get the address of system
.
Take this scenario as a road block:
The system variable does not exist in this case, we face a lot of unexpected challenges like this many times.
Let’s try to make use of System, mprotect and read ?, what are these things ??
The function mprotect() specifies the desired protection for the memory page(s) containing part or all of the interval [addr,addr+len-1]. If an access is disallowed by the protection given it, the program receives a SIGSEGV. prot is a bitwise-or of the following values.
Generally we make use of these variables which are possible to mark some memory area as writable and executable, read the shellcode from STDIN and direct execution there.
When checked for mprotect and read :
gdb-peda$ p mprotect
$3 = {<text variable, no debug info>} 0x80523e0 <mprotect>
gdb-peda$ p read
$4 = {<text variable, no debug info>} 0x80517f0 <read>
Good lord, they exist.
mprotect
takes three parameters: the memory address, the length in bytes, and a bitmap specifying the protection level. Let’s just call it on 4KB of the memory mapped to the binary and set the protection level to PROT_READ | PROT_WRITE | PROT_EXEC
.
If the exploit works , the program will SIGSEGV
with EIP pointing a range that will span for 4KB will be marked as rwx
.
Now let’s take a look at the memory layout so that we can mark the locations.. This is getting bigger and better
Machine credits: Vulnhub.com
To be continued Next week ( next Wednesday),
The Dark Knight of Security
Disclaimer:
I do not own the images in this blog post and all the images from Batman movies, Cartoons are owned by DC comics, WB and Christopher Nolan . Batman created by Bob Kane. All images represented here are for illustration and learning purpose to make this course a fun learning journey. I do not claim ownership of these images by any means.