Dynamic loader, plugins and shared object (code) security [seminar]

Task 1: Pugin

Although the dynamic linker allows to reach for the symbols defined in plugin, recovering plugin metadata is somewhat complicated, as (due to historical reasons) C does not mangle symbol names. Thus, the usual approach is to make both the core program and plugins include the same header, defining an interaction api.

  1. Create a common header hello_plugin.h, defining structure struct plugin_info. Have the structure define attributes:
    • const char *name,
    • uint32_t version.
  2. Create 3 plugins that include the common header and hold global variable hello_plugin_info, with attributes set to plugin's name and version defined as reference to macro constant VERSION.
  3. Compile the 3 plugins into idependent libraries (do not forget -Wl,-soname,GLOBALLY_UNIQUE_VALUE).
  4. Create a hello.c, that will try to dlopen() the 3 plugins one-by-one and print plugin name and version.
  5. Inspect the plugins using objdump -x and explain how did the global variable in plugin got it's value, given the section it resides in.
  6. Repeat the task, but this time make symbol plugin_info a function returning the requested info through value.

Task 2: rand() highjacking

A crutial task in cryptography is to generate sufficient random numbers.

  1. Create a preloaded library that hijacks rand() and after first 10 invokations starts returning always 9 as guaranteed by fair dice roll.
  2. Create test main, showing first 50 calls.

Task 3: Attack ssh-keygen with LD_PRELOAD

  1. Use strace to figure out how ssh-keygen generates public/private key pair.
  2. Identify the function for reading out random numbers.
  3. Feed the ssh-keygen non-random number pattern (i.e 0xaa).
  4. Implement the same API and same symbol in your malicious.so.
  5. Run several iterations of LD_PRELOAD=malicious.so ssh-keygen -f malicious_id_rsa. Pay attention to the image output, does it show the expected output?
  6. Debug, explain. You can even compile ssh-keygen locally, use nm, objdump -x, gdb.
In [ ]: