Last active
January 10, 2020 07:49
-
-
Save ozzi-/7dd920b126dad336d6243bbb8776a977 to your computer and use it in GitHub Desktop.
cross-platform privilege hardening for files with java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.BufferedReader; | |
import java.io.File; | |
import java.io.IOException; | |
import java.io.InputStreamReader; | |
import java.nio.file.Files; | |
import java.nio.file.Paths; | |
import java.nio.file.attribute.PosixFilePermission; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.HashSet; | |
import java.util.Set; | |
public class SecureFilePermissions { | |
public static void main(String[] args) { | |
String os = (System.getProperty("os.name")).toUpperCase(); | |
// illustrative purpose only | |
ArrayList<File> listOfFiles = youNeedToImplementThis(); | |
// set R+W for currently logged on user ONLY | |
setPermissions(os, listOfFiles); | |
} | |
private static void setPermissions(String os, ArrayList<File> listOfFiles) { | |
Thread thread = new Thread(new Runnable() { | |
@Override | |
public void run() { | |
for (File file : listOfFiles) { | |
String filePath = file.getAbsolutePath(); | |
if (file.isFile()) { | |
if (os.contains("WIN")) { | |
try { | |
setRWPermissionForCurrentUserForWindows(filePath); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
} else { | |
try { | |
if(os.contains("MAC")){ | |
deleteACLmacOS(filePath); | |
} | |
// macOS and GNU/Linux assumed to be POSIX compatible | |
setRWPermissionsForCurrentUserPosix(filePath); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
} | |
} | |
} | |
} | |
}); | |
thread.start(); | |
} | |
private static void deleteACLmacOS(String filePath) throws IOException, Exception { | |
Runtime rt = Runtime.getRuntime(); | |
Process pr = rt.exec(new String[]{"chmod","-N",filePath}); | |
handleExitValue(pr); | |
} | |
private static void setRWPermissionsForCurrentUserPosix(String filePath) throws Exception { | |
System.out.println("Setting permissions for " + filePath +" with java.nio"); | |
Set<PosixFilePermission> perms = new HashSet<PosixFilePermission>(); | |
perms.add(PosixFilePermission.OWNER_WRITE); | |
perms.add(PosixFilePermission.OWNER_READ); | |
try { | |
Path path = Paths.get(filePath); | |
// this only works when we are running as superuser | |
//PosixFileAttributeView view = Files.getFileAttributeView(path, PosixFileAttributeView.class); | |
//UserPrincipalLookupService service = path.getFileSystem().getUserPrincipalLookupService(); | |
//view.setOwner(service.lookupPrincipalByName(System.getProperty("user.name"))); | |
Files.setPosixFilePermissions(path, perms); | |
} catch (Exception e) { | |
throw new Exception("Failed to set permission using java nio posix due to " + e.getMessage() + " cause " + e.getCause() + " on " + filePath); | |
} | |
} | |
private static void setRWPermissionForCurrentUserForWindows(String filePath) throws Exception { | |
boolean useIcacls = checkForIcacls(); | |
System.out.println("Setting permissions for " + filePath + " with " + (useIcacls ? "icacls" : "cacls")); | |
Runtime rt = Runtime.getRuntime(); | |
// on systems with icacls, use it instead of the deprecated cacls | |
if (useIcacls) { | |
// reset to default inherited permissions, since we can't wipe them | |
Process pr = rt.exec("cmd.exe /c icacls \"" + filePath + "\" /T /Q /RESET"); | |
handleExitValue(pr); | |
// delete all inherited and force only current user RW priv | |
pr = rt.exec("cmd.exe /c icacls \"" + filePath + "\" /inheritance:r /grant:r \"%USERNAME%\":(RX,WA)"); | |
handleExitValue(pr); | |
} else { | |
// /p flag deletes all privileges then sets Read priv | |
Process pr = rt.exec("cmd.exe /c echo y|cacls \"" + filePath + "\" /p \"%USERNAME%\":R"); | |
handleExitValue(pr); | |
// /E /G adds to the current privileges the Write priv | |
pr = rt.exec("cmd.exe /c echo y|cacls \"" + filePath + "\" /E /G \"%USERNAME%\":W"); | |
handleExitValue(pr); | |
} | |
} | |
private static boolean checkForIcacls() { | |
try { | |
Runtime rt = Runtime.getRuntime(); | |
Process pr = rt.exec("where icacls"); | |
pr.waitFor(); | |
if (pr.exitValue() != 0) { | |
return false; | |
} | |
return true; | |
} catch (Exception e) { | |
e.printStackTrace(); | |
return false; | |
} | |
} | |
private static void handleExitValue(Process pr) throws IOException, Exception { | |
pr.waitFor(); | |
if (pr.exitValue() != 0) { | |
BufferedReader stdError = new BufferedReader(new InputStreamReader(pr.getErrorStream())); | |
String s = null; | |
String error = ""; | |
while ((s = stdError.readLine()) != null) { | |
error += s; | |
} | |
throw new Exception("Exit value = " + pr.exitValue() + " when running (I)CACLS. stdError = " + error); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment