Theme
Blocking executable uploads by content, not by extension
Some SFTP servers offer an extension exclusion list, so that administrators can name the file extensions users may not upload. That is a weak defense: an attacker uploads the executable with a harmless extension, renames it later, or finds another way to run it.
Because Syncplify Server! is scriptable, you can do a lot better than that: look at the content of every uploaded file, recognize an executable whatever it is called, and delete it on the spot.
Method 1: check the file's signature through the VFS
Many file types carry a fixed signature in their first bytes. A Windows executable starts with the two bytes 4D5A (MZ), and the four bytes at offset 60 hold, in little endian order, the offset of the PE header, which starts with 50450000 (PE\0\0). The script below reads those bytes through the VFS object, so it works on every VFS type, encrypted VFSs included, and deletes the file if both checks pass. Bind it to the AfterFileUpload event handler:
javascript
{
var vfs = GetCurrentVFS();
if (vfs != null) {
var path = CtxRelPath();
var head = vfs.ReadFileAsHex(path, 2);
if (head.Ok() && head.Data() == "4D5A") {
// the PE header offset is stored at byte 60, little endian
var ptr = vfs.ReadFileAsHex(path, 4, 60);
if (ptr.Ok() && ptr.Data().length == 8) {
var raw = ptr.Data();
var peOffset = parseInt(raw.substr(6, 2) + raw.substr(4, 2) + raw.substr(2, 2) + raw.substr(0, 2), 16);
var pe = vfs.ReadFileAsHex(path, 4, peOffset);
if (pe.Ok() && pe.Data() == "50450000") {
Log("Identified " + path + " as a Windows executable, deleting it");
var del = vfs.Remove(path);
if (!del.Ok()) {
Log("Failed to delete " + path + ": " + del.ErrorMsg());
}
}
}
}
}
}ReadFileAsHex(path, length, offset) returns the bytes as an uppercase hexadecimal string in a response object; always check Ok() before reading Data().
The script is an example for Windows executables, and it is easily adapted to other types. A ZIP archive, for instance, starts with 504B0304. Many file types can be told apart this way.
Method 2: FileType
Since version 6, SyncJS also has a FileType function that identifies the MIME type of hundreds of file types by reading at most the first 261 bytes of a file. It works on the operating system's file system, so it needs the absolute local path of the file, which exists only for a Disk VFS, and on an encrypted VFS it would see the encrypted bytes. Where that is fine, the script becomes:
javascript
{
var absPath = Session.GetAbsPath();
if (FileType(absPath) == "application/vnd.microsoft.portable-executable") {
Log("Identified " + absPath + " as a Windows executable, deleting it");
if (DelFile(absPath)) {
Log("Deleted: " + absPath);
} else {
Log("Failed to delete: " + absPath);
}
}
}Session.GetAbsPath() is the session's live path cursor, which is the uploaded file when this script runs right on AfterFileUpload. The MIME type for a Windows executable is application/vnd.microsoft.portable-executable.