CVE-2020-9273 PoC
ProFTPd Post-Auth Use-After-Free leading to Remote Code Execution
[%] Usage: python3 exploit.py <target IP> <target port> <callback IP> <callback port> <username> <password>
Vulnerability trigger requirements:
- Valid credentials for a user
Exploitation requirements:
- ProFTPd with
mod_copy
enabled
Introduction
There exists a Use-After-Free in ProFTPd that can be triggered when interrupting through command channel while a transference is active in the data channel.
Shout out to Antonio Morales (@nosoynadiemas) for discovering this vulnerability, you can find more information on the discovery in this post.
The result of triggering the Use-After-Free is controlling useful data from the program with custom values.
Unfortunately, the vulnerability requires pre-auth to be triggered
Leaking memory addresses
Due to the charasteristics of this vulnerability, a leak is really difficult as we require to disconnect from target server to trigger the bug, this means the exploitation process and execution flow of the program is the closing and cleanup process before finishing session.
So, to make this vulnerability possible to be exploited, and as we need predictable memory addresses I remembered that /proc/self/maps
can be accessed from any process even with low privileges.
I tried to retrieve it using the data channel but something went wrong... stat returns 0 as it is a pseudo-file, so 0 bytes are transferred back to client
My solution to this was compiling the module with mod_copy
, we can copy /proc/self/maps
to /tmp
and then perform a normal transfer
This the best leak an attacker could get as it gives you every segment address range, also, knowing filenames you can sometimes guess libc version by the filename (Eg.: libc-2.31.so
)
Hijacking control flow
The exploitation part was somewhat limited, and primitives like arbitrary read, or write-what-where were not possible, instead, non-fully-controllable addresses could be written in arbitrary addresses.
Also, as we control pool-related structs we can move pools to pivot the pool somewhere else to arbitrary addresses, unfortunately, we have only once chance (one allocation) to do that as the rest of allocations against our controlled pool are non-controlled strings, most of them for responses
After finding different ways that could allow me to hijack execution flow, I found one that could be interesting which is corrupting cmd->tmp_pool
, we can control cmd->tmp_pool->cleanups
so when destroy_pool(cmd->tmp_pool)
is called our fake cleanup_t
struct would be interpreted.
Unfortunately, it turned out to be difficult to control as a string with value: displayable-str
is appended after our arbitrary address, also due to the way bytes are copied (using string-based functions) we can just enter a single address.
The result is that crashes can happen when reaching destroy_pool()
.
@DUKPT_ who is also working on a PoC for this vulnerability, had the idea to overwrite gid_tab->pool
, which is also passed to destroy_pool()
.
I decided to go this way as it is more reliable, so shout out to @DUKPT_ for his work on this.
The target with all these techniques is to make run_cleanups()
interpret our custom fake cleanup_t
struct, which allow us to get custom RIP and RDI values.
Once you get arbitrary RIP and RDI you can follow any method you would like to get RCE
Method 1: Stack pivot, ROP and shellcode execution
You can:
- Use RIP to jump to an stack pivot gadget like
push rdi ; pop rsp ...
- As you control RDI aswell you will be able to control stack to your ROPchain
- Finally you will be able to execute a custom shellcode using
mprotect()
+ jump to shellcode in heap (onceRWX
privileges set).
Method 2: ret2libc, ret2X
You can jump to any function that requires one argument, like system()
does. Or reuse arguments at the time of run_cleanups()
jumping to code
Example: execute netcat with reverse shell using system()
and pointing rdi to the command string on heap.
Reproduce
- Initialize proftpd (compiled binary present too)
- Make sure proftpd.conf is the same as yours
- Execute this PoC against ProFTPd server (using any user credentials)
- Enjoy shell