There is nothing special happening in the Core when uploading an image.
One of the first steps that is taken is to grab the inputstream, write in a temp file so all image operations can be done on the temp file, using code similar to below:
private static File copyImageToTempFile(final InputStream inputStream) throws PrivilegedActionException, IOException
File tempImage = AccessController.doPrivileged(createTempFile());
FileOutputStream outputStream = AccessController.doPrivileged(openFileOutputStream(tempImage));
As you can see nothing special is happening there. I've had some experience with transferring files through ftp, and noticed that if something happens during the transfer (a file is incomplete or corrupted) the transfer could 'freeze' as you are describing.
I would recommend taking control over that transfer process and write the files to a temp folder first before loading them into an actual image. That way you can track exactly what is happening, what takes a long time and if you want to go further you can even try adding time-outs to the transfer so you can prevent this all together.
I have used FTP and SFTP quite a lot and I also have had problems with FTP processes never finishing.
One work around is to have multiple scheduled events. So instead of a SEF that triggers every hour create four SEF's that trigger every four hours. This way when a SEF never finishes it does not matter directly because we still have 3 SEF's that do run.
The other fix is to go to SFTP (FTP over SSH, not to mix up FTP over SSL). There is a SFTP module in the store. I have never experienced SEF's not finishing with that module. The only problem is that the other party needs a FTP server that supports SFTP and not all do.