pwnscripts icon indicating copy to clipboard operation
pwnscripts copied to clipboard

running libc properly

Open 152334H opened this issue 3 years ago • 2 comments

As I outlined in a writeup:

So far I have tried

  • Using LD_PRELOAD, which in the correct order (ld-linux.so first) will run the binary without crashing, although other issues still surface
  • Running ./ld-linux.so, as outlined in the writeup. This has numerous side effects, including the actual binary getting allocated to an 0x7f.* page instead of the expected 0x5.* address
  • LD_LIBRARY_PATH, which is finicky enough that I have not investigated it throughly in the past

Additional suggestions from https://github.com/152334H/pwnscripts/issues/9#issuecomment-713248248_

There are several ways to resolve this issue:
1. Set up a ubuntu18-04 docker environment
2. Use patchelf to change the path of interpreter and and library path
3. (The ugly way but the way i used most frequently other than docker) use vim to edit the binary directly to change the interpreter to ./ld.so and libc to ./libcccc (it's ./libcccc because it has the same number of letters as libc.so.6)
4. Run the binary as LD_PRELOAD=./libc.so.6 ./ld.so <challenge>. But this method will treat the challenge as a library so you end up with a different memory layout from normal execution

152334H avatar Oct 21 '20 03:10 152334H

An analysis of libc simulation methods

Every method here is analysed with mapcheck.c:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(){
  int pid = getpid();
  char s[512];
  sprintf(s, "cat /proc/%d/maps", pid);
  system(s);
  printf("%p\n", printf);
}

And ultimately, a fully correct sample should look like:

557ab6fa4000-557ab6fa5000 r-xp 00000000 09:01 27263875                   /home/a/mapcheck.orig
557ab71a4000-557ab71a5000 r--p 00000000 09:01 27263875                   /home/a/mapcheck.orig
557ab71a5000-557ab71a6000 rw-p 00001000 09:01 27263875                   /home/a/mapcheck.orig
7f7d921de000-7f7d92203000 r--p 00000000 09:01 5244220                    /usr/lib/x86_64-linux-gnu/libc-2.31.so
7f7d92203000-7f7d9237b000 r-xp 00025000 09:01 5244220                    /usr/lib/x86_64-linux-gnu/libc-2.31.so
7f7d9237b000-7f7d923c5000 r--p 0019d000 09:01 5244220                    /usr/lib/x86_64-linux-gnu/libc-2.31.so
7f7d923c5000-7f7d923c6000 ---p 001e7000 09:01 5244220                    /usr/lib/x86_64-linux-gnu/libc-2.31.so
7f7d923c6000-7f7d923c9000 r--p 001e7000 09:01 5244220                    /usr/lib/x86_64-linux-gnu/libc-2.31.so
7f7d923c9000-7f7d923cc000 rw-p 001ea000 09:01 5244220                    /usr/lib/x86_64-linux-gnu/libc-2.31.so
7f7d923cc000-7f7d923d2000 rw-p 00000000 00:00 0
7f7d923dc000-7f7d923dd000 r--p 00000000 09:01 5244212                    /usr/lib/x86_64-linux-gnu/ld-2.31.so
7f7d923dd000-7f7d92400000 r-xp 00001000 09:01 5244212                    /usr/lib/x86_64-linux-gnu/ld-2.31.so
7f7d92400000-7f7d92408000 r--p 00024000 09:01 5244212                    /usr/lib/x86_64-linux-gnu/ld-2.31.so
7f7d92409000-7f7d9240a000 r--p 0002c000 09:01 5244212                    /usr/lib/x86_64-linux-gnu/ld-2.31.so
7f7d9240a000-7f7d9240b000 rw-p 0002d000 09:01 5244212                    /usr/lib/x86_64-linux-gnu/ld-2.31.so
7f7d9240b000-7f7d9240c000 rw-p 00000000 00:00 0
7ffffd143000-7ffffd164000 rw-p 00000000 00:00 0                          [stack]
7ffffd17c000-7ffffd17f000 r--p 00000000 00:00 0                          [vvar]
7ffffd17f000-7ffffd180000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall]
0x7f7d92242e10

./ld-linux.so --library-path

Benefits

  • Very easy to run, so long as libc-database is present
  • Works well with multiple libraries

Issues

  • Mappings are all at 0x7f.*. This is evidently wrong for the binary itself, which should always start at 0x5.*.
  • Address offsets are, on rare occasions, wrong. This was discovered during N1CTF 2020

Sample

7fbcc316b000-7fbcc3190000 r--p 00000000 09:01 27283362                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/libc.so.6
7fbcc3190000-7fbcc3308000 r-xp 00025000 09:01 27283362                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/libc.so.6
7fbcc3308000-7fbcc3352000 r--p 0019d000 09:01 27283362                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/libc.so.6
7fbcc3352000-7fbcc3353000 ---p 001e7000 09:01 27283362                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/libc.so.6
7fbcc3353000-7fbcc3356000 r--p 001e7000 09:01 27283362                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/libc.so.6
7fbcc3356000-7fbcc3359000 rw-p 001ea000 09:01 27283362                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/libc.so.6
7fbcc3359000-7fbcc335f000 rw-p 00000000 00:00 0
7fbcc335f000-7fbcc3360000 r-xp 00000000 09:01 27263875                   /home/a/mapcheck.orig
7fbcc3360000-7fbcc355f000 ---p 00001000 09:01 27263875                   /home/a/mapcheck.orig
7fbcc355f000-7fbcc3560000 r--p 00000000 09:01 27263875                   /home/a/mapcheck.orig
7fbcc3560000-7fbcc3561000 rw-p 00001000 09:01 27263875                   /home/a/mapcheck.orig
7fbcc3561000-7fbcc3562000 r--p 00000000 09:01 27283356                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/ld-linux-x86-64.so.2
7fbcc3562000-7fbcc3585000 r-xp 00001000 09:01 27283356                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/ld-linux-x86-64.so.2
7fbcc3585000-7fbcc358d000 r--p 00024000 09:01 27283356                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/ld-linux-x86-64.so.2
7fbcc358e000-7fbcc358f000 r--p 0002c000 09:01 27283356                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/ld-linux-x86-64.so.2
7fbcc358f000-7fbcc3590000 rw-p 0002d000 09:01 27283356                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/ld-linux-x86-64.so.2
7fbcc3590000-7fbcc3591000 rw-p 00000000 00:00 0
7ffd0bf6e000-7ffd0bf8f000 rw-p 00000000 00:00 0                          [stack]
7ffd0bff9000-7ffd0bffc000 r--p 00000000 00:00 0                          [vvar]
7ffd0bffc000-7ffd0bffd000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall]
0x7fbcc31cfe10

LD_PRELOAD="/path/to/ld-linux /path/to/libc"

Benefits

  • PIE addresses are correctly at 0x5.*, unlike ./ld-linux
  • libc-database is (technically) not needed for this, so long as both ld-linux & libc.so.6 are linked with the challenge

Issues

  • need to do extra programming if extra libraries on top of libc.so.6 are used (alternatively, use LD_PRELOAD & LD_LIBRARY_PATH simultaneously)
  • mapping is still wrong --- ld-2.31.so is included twice, plus (discovered outside of this example) heap addresses are put after the first ld-2.31.so.
  • untested on the breaking N1CTF example

Sample

558660142000-558660143000 r-xp 00000000 09:01 27263875                   /home/a/mapcheck.orig
558660342000-558660343000 r--p 00000000 09:01 27263875                   /home/a/mapcheck.orig
558660343000-558660344000 rw-p 00001000 09:01 27263875                   /home/a/mapcheck.orig
7f647cb8c000-7f647cb8f000 rw-p 00000000 00:00 0
7f647cb8f000-7f647cbb4000 r--p 00000000 09:01 27283362                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/libc.so.6
7f647cbb4000-7f647cd2c000 r-xp 00025000 09:01 27283362                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/libc.so.6
7f647cd2c000-7f647cd76000 r--p 0019d000 09:01 27283362                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/libc.so.6
7f647cd76000-7f647cd77000 ---p 001e7000 09:01 27283362                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/libc.so.6
7f647cd77000-7f647cd7a000 r--p 001e7000 09:01 27283362                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/libc.so.6
7f647cd7a000-7f647cd7d000 rw-p 001ea000 09:01 27283362                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/libc.so.6
7f647cd7d000-7f647cd81000 rw-p 00000000 00:00 0
7f647cd81000-7f647cd82000 r--p 00000000 09:01 27283355                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/ld-2.31.so
7f647cd82000-7f647cda5000 r-xp 00001000 09:01 27283355                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/ld-2.31.so
7f647cda5000-7f647cdad000 r--p 00024000 09:01 27283355                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/ld-2.31.so
7f647cdad000-7f647cdae000 ---p 0002c000 09:01 27283355                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/ld-2.31.so
7f647cdae000-7f647cdaf000 r--p 0002c000 09:01 27283355                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/ld-2.31.so
7f647cdaf000-7f647cdb0000 rw-p 0002d000 09:01 27283355                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/ld-2.31.so
7f647cdb0000-7f647cdb3000 rw-p 00000000 00:00 0
7f647cdb3000-7f647cdb4000 r--p 00000000 09:01 5244212                    /usr/lib/x86_64-linux-gnu/ld-2.31.so
7f647cdb4000-7f647cdd7000 r-xp 00001000 09:01 5244212                    /usr/lib/x86_64-linux-gnu/ld-2.31.so
7f647cdd7000-7f647cddf000 r--p 00024000 09:01 5244212                    /usr/lib/x86_64-linux-gnu/ld-2.31.so
7f647cde0000-7f647cde1000 r--p 0002c000 09:01 5244212                    /usr/lib/x86_64-linux-gnu/ld-2.31.so
7f647cde1000-7f647cde2000 rw-p 0002d000 09:01 5244212                    /usr/lib/x86_64-linux-gnu/ld-2.31.so
7f647cde2000-7f647cde3000 rw-p 00000000 00:00 0
7ffc3e895000-7ffc3e8b6000 rw-p 00000000 00:00 0                          [stack]
7ffc3e90e000-7ffc3e911000 r--p 00000000 00:00 0                          [vvar]
7ffc3e911000-7ffc3e912000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall]
0x7f647cbf3e10

patchelf --set-interpreter $ld --replace-needed libc.so.6 $libc ./binary

Benefits

  • Closest mapping to the original
  • libc-database also technically unecessary

Issues

  • Requires modification of the binary itself
  • Untested on N1CTF example
  • Requires patchelf

Sample

55fe4bbc8000-55fe4bbc9000 r-xp 00000000 09:01 27263874                   /home/a/mapcheck.out
55fe4bdc8000-55fe4bdc9000 r--p 00000000 09:01 27263874                   /home/a/mapcheck.out
55fe4bdc9000-55fe4bdca000 rw-p 00001000 09:01 27263874                   /home/a/mapcheck.out
55fe4bdca000-55fe4bdcb000 rw-p 00003000 09:01 27263874                   /home/a/mapcheck.out
7f34f3bad000-7f34f3baf000 rw-p 00000000 00:00 0
7f34f3baf000-7f34f3bd4000 r--p 00000000 09:01 27283362                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/libc.so.6
7f34f3bd4000-7f34f3d4c000 r-xp 00025000 09:01 27283362                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/libc.so.6
7f34f3d4c000-7f34f3d96000 r--p 0019d000 09:01 27283362                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/libc.so.6
7f34f3d96000-7f34f3d97000 ---p 001e7000 09:01 27283362                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/libc.so.6
7f34f3d97000-7f34f3d9a000 r--p 001e7000 09:01 27283362                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/libc.so.6
7f34f3d9a000-7f34f3d9d000 rw-p 001ea000 09:01 27283362                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/libc.so.6
7f34f3d9d000-7f34f3da3000 rw-p 00000000 00:00 0
7f34f3da3000-7f34f3da4000 r--p 00000000 09:01 27283355                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/ld-2.31.so
7f34f3da4000-7f34f3dc7000 r-xp 00001000 09:01 27283355                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/ld-2.31.so
7f34f3dc7000-7f34f3dcf000 r--p 00024000 09:01 27283355                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/ld-2.31.so
7f34f3dd0000-7f34f3dd1000 r--p 0002c000 09:01 27283355                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/ld-2.31.so
7f34f3dd1000-7f34f3dd2000 rw-p 0002d000 09:01 27283355                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/ld-2.31.so
7f34f3dd2000-7f34f3dd3000 rw-p 00000000 00:00 0
7ffcbdcf2000-7ffcbdd13000 rw-p 00000000 00:00 0                          [stack]
7ffcbdd44000-7ffcbdd47000 r--p 00000000 00:00 0                          [vvar]
7ffcbdd47000-7ffcbdd48000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall]
0x7f34f3c13e10

152334H avatar Oct 27 '20 11:10 152334H

Test two: easyWrite clone (tcache_perthread_struct writing)

Because I have a machine available with libc6_2.31-0ubuntu9.1_amd64, all these tests are done on that version of libc.

Every method here is analysed with tcache.c:

#include <stdlib.h>
#define MALLOC_OFF 0x9d260
#define TCACHE_OFF 0x7ffff7fc04f0-0x7ffff7dcd000
#define F_HOOK_OFF 0x1eeb28
#define TCACHE_MAX_BINS 0x40

typedef struct tcache_struct {
      short counts[TCACHE_MAX_BINS];
      void *entries[TCACHE_MAX_BINS];
} tcache_struct;
void win(){ puts("success"); }
int main(){
    malloc(1);
    tcache_struct constructed_tcache = (tcache_struct) { .counts = {0, 0, 1}, .entries = {0,0, malloc-MALLOC_OFF+F_HOOK_OFF}};
    tcache_struct **tcache = malloc-MALLOC_OFF+TCACHE_OFF;
    *tcache = &constructed_tcache;
    puts("fake tcache in place");
    void *p = malloc(0x30);
    puts("overwriting free_hook");
    *(long long*)p = win;
    free(p);
}

And ultimately, a fully correct sample should look like:

fake tcache in place
overwriting free_hook
success

./ld-linux.so --library-path

fake tcache in place
overwriting free_hook

The program just ends. This matches up with what I experienced in N1CTF.

LD_PRELOAD="/path/to/ld-linux /path/to/libc"

Segmentation fault

This method terminates immediately when trying to deference **tcache. This happens because of the difference between the expected memory allocation:

7f7d923c9000-7f7d923cc000 rw-p 001ea000 09:01 5244220                    /usr/lib/x86_64-linux-gnu/libc-2.31.so
7f7d923cc000-7f7d923d2000 rw-p 00000000 00:00 0
7f7d923dc000-7f7d923dd000 r--p 00000000 09:01 5244212                    /usr/lib/x86_64-linux-gnu/ld-2.31.so

And the actual memory allocation:

7f647cd7a000-7f647cd7d000 rw-p 001ea000 09:01 27283362                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/libc.so.6
7f647cd7d000-7f647cd81000 rw-p 00000000 00:00 0
7f647cd81000-7f647cd82000 r--p 00000000 09:01 27283355                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/ld-2.31.so

For the latter, the page allocated for the unlabelled .tls map is contiguous (!) with that of ld-linux, whereas in the expected behavior, it isn't.

patchelf --set-interpreter $ld --replace-needed libc.so.6 $libc ./binary

fake tcache in place
overwriting free_hook

Like the ./ld-linux.so method, the program just ends.

7f34f3d9a000-7f34f3d9d000 rw-p 001ea000 09:01 27283362                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/libc.so.6
7f34f3d9d000-7f34f3da3000 rw-p 00000000 00:00 0
7f34f3da3000-7f34f3da4000 r--p 00000000 09:01 27283355                   /home/a/libc-database/libs/libc6_2.31-0ubuntu9.1_amd64/ld-2.31.so

The second line here matches with the expected allocation, but because ld-2.31.so is still contiguous, the write fails to affect the tcache.

152334H avatar Oct 27 '20 16:10 152334H