Gallopsled / pwntools

CTF framework and exploit development library
http://pwntools.com
Other
11.74k stars 1.67k forks source link

pwn checksec: do not require libunicorn to be loaded #2343

Closed disconnect3d closed 5 months ago

disconnect3d commented 5 months ago

It seems that pwn checksec requires libunicorn. Is that really required? The Unicorn Engine mmaps a 1GB+ memory page which aborts the program on failures. This can happen on low-memory systems such as cheap VPSes. This is actually a bug in libunicorn that I reported in https://github.com/unicorn-engine/unicorn/issues/1766 but it still hasn't been fixed.

Given all this, it would be great if we could not require libunicorn in checksec. But if we need, it would be nice to get it documented here for users who stumble upon the same issue and try to search it here.

Here is an example issue of this:

root@pwndbg:~# free -h
               total        used        free      shared  buff/cache   available
Mem:           957Mi       265Mi       153Mi       4.0Mi       538Mi       532Mi
Swap:             0B          0B          0B

root@pwndbg:~# strace -e openat,mmap pwn checksec /root/x/bin/main 2>&1 | tail -n 10
openat(AT_FDCWD, "/usr/lib/python3/dist-packages/mpmath-0.0.0.egg-info/PKG-INFO", O_RDONLY|O_CLOEXEC) = 7
openat(AT_FDCWD, "/usr/local/lib/python3.10/dist-packages/unicorn/lib/libunicorn.so.2", O_RDONLY|O_CLOEXEC) = 7
mmap(NULL, 22447520, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 7, 0) = 0x7f2604f9d000
mmap(0x7f2605339000, 13496320, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 7, 0x39c000) = 0x7f2605339000
mmap(0x7f2606018000, 3039232, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 7, 0x107b000) = 0x7f2606018000
mmap(0x7f26062fe000, 1601536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 7, 0x1360000) = 0x7f26062fe000
mmap(0x7f2606485000, 525728, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f2606485000
mmap(NULL, 1073741824, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = -1 ENOMEM (Cannot allocate memory)
Could not allocate dynamic translator buffer
+++ exited with 1 +++
disconnect3d commented 5 months ago

This issue happens because checksec.py invokes the ELF object constructor that calls its self._populate_plt() function that invokes Unicorn engine to emulate PLT instructions to figure out some addresses.

Funnily, modifying the code so that the _populate_plt fail, for example by introducing a line: asdf which causes a name 'asdf' is not defined error, makes the checksec command work, because it handles the error and logs a warning:

https://github.com/Gallopsled/pwntools/blob/b2cba039d4d07eb8b8c98369fd69dcd13ae80441/pwnlib/elf/elf.py#L352-L355