Skip to content

Instantly share code, notes, and snippets.

@ozzi-
Last active January 10, 2020 07:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ozzi-/7dd920b126dad336d6243bbb8776a977 to your computer and use it in GitHub Desktop.
Save ozzi-/7dd920b126dad336d6243bbb8776a977 to your computer and use it in GitHub Desktop.
cross-platform privilege hardening for files with java
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