@gnothiseauton No decompilation or heavy reverse engineering is necessary in this case, as Samba is open source.
As noted by CVE - CVE-2007-2447 the vulnerable versions are 3.0.0 through 3.0.25rc3. You can find most of those old versions at Index of /pub/samba/stable. I happened to grab 3.0.20.
It’s a fairly big project, so instead of crawling through all the files by hand:
root@kali:/media/sf_shared/samba-3.0.20# grep -R "map script" *
-*- snip -*-
source/lib/username.c: /* first try the username map script */
-*- snip -*-
Taking a look at that file, we see this:
/* first try the username map script */
if ( *cmd ) {
char **qlines;
pstring command;
int numlines, ret, fd;
pstr_sprintf( command, "%s \"%s\"", cmd, user );
DEBUG(10,("Running [%s]\n", command));
ret = smbrun(command, &fd);
DEBUGADD(10,("returned [%d]\n", ret));
So it’s just putting the supplied username onto the end of a command string (cmd
in this case is /etc/samba/scripts/mapusers.sh
as set by the config file) and then tossing that into smbrun()
. Okay, so where’s smbrun()
?
root@kali:/media/sf_shared/samba-3.0.20# grep -R "smbrun(" *
-*- snip -*-
source/lib/smbrun.c:This is a utility function of smbrun().
source/lib/smbrun.c:int smbrun(char *cmd, int *outfd)
-*- snip -*-
That function just does a bunch of process/permissions housekeeping, and then right at the very bottom:
execl("/bin/sh","sh","-c",cmd,NULL);
/* not reached */
exit(82);
return 1;
Browsing through the code above this, it’s very clear that the cmd
variable is never sanitized. So user
(our input) gets put directly into cmd
, then cmd
gets tossed directly into execl()
, giving us command execution via:
sh -c /etc/samba/scripts/mapusers.sh "our_input_here"
Note: I actually messed up the quotation marks in my previous post, but it doesn’t even matter because of how straightforward this vulnerability is.
If you take a look at a newer, fixed version of Samba you’ll instead see that smbrun()
is now just a wrapper function which calls smbrun_internal()
with the sanitize
argument set to True
. What’s that do? Well, back to the execl()
call:
const char *newcmd = sanitize ? escape_shell_string(cmd) : cmd;
if (!newcmd) {
exit(82);
}
execl("/bin/sh","sh","-c",newcmd,NULL);
Easy peasy. Two greps and some patience and anyone could stumble on dumb vulnerabilities like this.