Bonjour,
Je vais terminer nebulla d'ici quelques jours je suis juste pas trop disponible en ce moment à cause de pas mal de projet plutôt cool .
Une fois que tout sera calmé je me lancerais dans de l'analyse plus fun à base de compréhension d'un framework plutôt cool nommé Volatilty.
En attendant je me prépare pour le #cccamp15 !
A très bientôt.
lundi 10 août 2015
dimanche 26 juillet 2015
Nebulla - level 16
Bonjour,
Nous avons presque
terminé avec cette liste d'exploit nous en sommes au niveau 16
maintenant voila ce que l'on nous donne :
Donc logiquement voici le script perl qui va tourner sur le port 1616:There is a perl script running on port 1616.
To do this level, log in as the level16 account with the password level16. Files for this level can be found in /home/flag16.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | #!/usr/bin/env perl use CGI qw{param}; print "Content-type: text/html\n\n"; sub login { $username = $_[0]; $password = $_[1]; $username =~ tr/a-z/A-Z/; # conver to uppercase $username =~ s/\s.*//; # strip everything after a space @output = `egrep "^$username" /home/flag16/userdb.txt 2>&1`; foreach $line (@output) { ($usr, $pw) = split(/:/, $line); if($pw =~ $password) { return 1; } } return 0; } sub htmlz { print("<html><head><title>Login resuls</title></head><body>"); if($_[0] == 1) { print("Your login was accepted<br/>"); } else { print("Your login failed<br/>"); } print("Would you like a cookie?<br/><br/></body></html>\n"); } htmlz(login(param("username"), param("password"))); |
On peut voir une ligne de code (ligne 14) qui semble être sensible à une injection. En se basant sur une faille relativement connu appelé Poisoin Null byte . Notre but sera donc de tenter d’exécuter une commande de notre choix (dans le meilleur des cas pour avoir un terminal simplement. Et puisque nous sommes sur un script qui est exécuté sur un port donné on va devoir ici utiliser netcat . Donc dans un premier temps nous allons simplement executer le script pour voir ce qu'il nous indique :
Et donc puisque nous n'avons pas la moindre idée du couple de login/password on se retrouve avec un message d'erreur ici. J'ai utilisé une simple request HTTP (je vous conseil de regarder la RFC si vous ne comprenez pas ce que j'ai fais). Maintenant en regardant le petit script on peut se rendre compte que nos arguments seront modifié (les commentaires dans le script sont cool pour aider dans la compréhension ici). On va donc simplement créer un petit script en bash qui va simplement exécuter netcat en mode listen (sur le port 4242 ici) qui utilisera un programme en inbound (ici le lancement d'un shell). On peut se rendre compte que pour accéder à ce script un simple ls nous prouve que l'on va trouver uniquement ce script si on va chercher dans /*/NAMEOFSCRIPT . J'ai utilisé netcat.traditional ici puisque lors de l’exécution de la commande netcat simple. Voici donc notre script :
Et donc nous allons simplement utiliser ce script dans la partie username histoire de faire l'injection correctement (avec la faille null byte ici). Enfin nous avons simplement à nous connecter sur le port ouvert depuis l’exécution du script pour récupérer le flag.
Et voila rien de vraiment nouveau.
Nebulla - level 15
Bonjour,
Nous voila au niveau
15 ici. Voyons voir ce qu'on nous donne ici :
strace the binary at /home/flag15/flag15 and see if you spot anything out of the ordinary.
You may wish to review how to “compile a shared library in linux” and how the libraries are loaded and processed by reviewing the dlopen manpage in depth.
Clean up after yourself :)
To do this level, log in as the level15 account with the password level15. Files for this level can be found in /home/flag15.
On nous indique
clairement d'apprendre à utiliser strace ici qui est un programme
qui va permettre de savoir les syscalls utilisé par notre programme
au minimum. On va donc simplement lancer cette commande pour voir ce
que nous donne le résultat.
On peut remarquer
très vite que le programme tente d'utiliser des fichiers qui ne sont
pas présent ici. Ces fichiers sont situé dans le dossier
/var/tmp/flag15. On va alors tenter d'en savoir plus sur ce fichier
avec la fameuse commande objdump qui va nous permettre de tout savoir
sur le programme visé. On va ici tenter de regarder ce qu'il se
passe au niveau des librairies puisqu'on nous a bien précisé de
chercher à comprendre comment fonctione tout ce qui est lié aux «
a shared library in linux ». Dans un premier temps on va voir
les libs utilisé obligatoirement.
Ici dans la partie
lib dynamique on peut lire le nom du fichier libc.so.6 dans le
dossier /var/tmp/flag15 on peut aussi tenter de savoir les fonctions
utilisé ici :
Avec quelques
recherche sur le net on peut faire simplement notre petite libraire
perso avec notre fonction __libc_start_main() tel que :
La compilation peut faire peur mais avec un peu de recherche il s’agit simplement des flags nécessaire pour rendre notre librairie possible d'utilisation. Ici il semblerait qu'il manque une fonction obligatoire ici __cxa_finalize que je vais donc rajouter simplement ici :
On se retrouve encore une autre erreur lié à la version de GLIBC. Au dessus par objdump on a pu voir que la version utilisé ici est simplement la 2.0. On va donc améliorer ça avec des flags en plus !
Alors j'ai trouvé tout les flags après des recherches sur internet (je suis pas devin) je vous conseil de tenter de comprendre tout ça de votre coté. On se retrouve encore avec des erreurs.. Bon on va donc utiliser une manière un peu bourrin qui va nous permettre d'afficher simplement tout les messages de debug sur un fichier utilisé pour ca je vais donc simplement copier le binaire et le lancer avec la variable global LD_DEBUG set à all et donc:
J'ai coupé une partie puisque ce qui nous intéresse se trouve ici. Et donc on peut remarquer que tout est bon ici jusqu'au call de system qui n'existe simplement pas pour l'ordinateur. On va donc devoir rajouter encore des flags pour corriger ce problème dans le but d'override simplement la partie que l'on souhaite sans toucher au reste!
On a enfin réussis à utiliser notre fonction system sans soucis puisque celle-ci s’exécute au lancement de notre programme. Le soucis ici c'est que notre programme garde l'uid de l'utilisateur qui va lancer le programme et non l'uid du programme en lui même. Pour résoudre ce soucis on va modifier un petit peu notre script ainsi:
Et enfin voila notre petit flag !
Ce niveau est vraiment sympa puisqu'il nous oblige à utiliser ce qu'on a pu déjà utiliser par le passé mais de façon plus approfondi. Ainsi on a pu découvrir objdump ainsi que strace qui sont vraiment utile surtout dans l'applicatif. Donc prenez vraiment le temps de comprendre l'utilisation de ces programmes.
vendredi 24 juillet 2015
Nebulla - level 14
Bonjour,
Nous voila au niveau 14 qui semble différent de loin. On nous demande ici :
Ici nous n'avons pas de source uniquement un fichier exécutable qui va encrypter des données passé en paramètre ainsi qu'un fichier crypter qui doit reprendre l'algo utilisé par le programme précédent. Donc il va simplement comprendre comment fonctionne l’encryption ici. Le test le plus simple sera d'écrire plusieurs fois le même caractère. On va donc tester ca :
On peut assez simplement comprendre le fonctionnement de l'algo qui va dépendre de la taille en s'incrémentant après chaque caractère. On va donc créer un simple mini logiciel pour decrypter le fichier token qui contient notre clef :
Nous voila au niveau 14 qui semble différent de loin. On nous demande ici :
This program resides in /home/flag14/flag14. It encrypts input and writes it to standard output. An encrypted token file is also in that home directory, decrypt it :)
To do this level, log in as the level14 account with the password level14. Files for this level can be found in /home/flag14.
Ici nous n'avons pas de source uniquement un fichier exécutable qui va encrypter des données passé en paramètre ainsi qu'un fichier crypter qui doit reprendre l'algo utilisé par le programme précédent. Donc il va simplement comprendre comment fonctionne l’encryption ici. Le test le plus simple sera d'écrire plusieurs fois le même caractère. On va donc tester ca :
On peut assez simplement comprendre le fonctionnement de l'algo qui va dépendre de la taille en s'incrémentant après chaque caractère. On va donc créer un simple mini logiciel pour decrypter le fichier token qui contient notre clef :
Je vous donne le
petit programme basique ici :
#include <stdio.h> #include <string.h> int main(int ac, char **av) { int i; i = -1; while (++i < strlen(av[1])) printf("%c", av[1][i] - i); printf("\n"); return (0); }
Rien de très
compliqué on pourrait tenter de reverse le programme pour comprendre
l'algo mais parfois avec un simple test très basique on peut trouver
le fonctionnement d'un programme.
Nebulla - level 13
Bonjour,
Nous allons faire ce niveau 13 donc sans plus tarder voyons ce qu'on nous donne ici :
Nous allons faire ce niveau 13 donc sans plus tarder voyons ce qu'on nous donne ici :
There is a security check that prevents the program from continuing execution if the user invoking it does not match a specific user id.
To do this level, log in as the level13 account with the password level13. Files for this level can be found in /home/flag13.
Donc nous avons
aussi un fichier source relativement simple :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #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); } |
Donc avec ce code
source on voit assez rapidement que si on execute le programme il va
avoir du mal à passer le premier test. Notre uid sera différent du
uid demandé et donc nous sommes stop par cette simple condition :
#define FAKEUID 1000 if(getuid() != FAKEUID)
Comme l'indique ma démonstration notre id de base est à 1014 :
La technique que
l'on va utiliser ici est toute simple on va simplement changer la
fonction getuid() du système par notre propre fonction et pour ça
on va devoir modifier une variable qui va permettre de simplement
pouvoir forcer la librairie utiliser lors de l'exécution de notre programme. Donc on
va déjà créer notre fonction qui va remplacer getuid :
#include <sys/types.h> uid_t getuid(void) { return (1000); }
Nous allons ensuite
compiler cette lib avec gcc et différent flag qui vont permettre de
rendre cette libraire utilisable. On va enfin adapté notre
LD_PRELOAD pour forcer l'utilisation de la librairie et on va enfin
lancer notre exécutable. Si tout fonctionne on va avoir alors un
password que l'on va devoir utiliser pour se log et enfin récupérer
notre flag :
Je vous conseil de bien comprendre ce procéder puisqu'il est fort utile dans ce genre de cas. On peut trouver pas mal d'exemple et d'explication sur le net.
Je vous conseil de bien comprendre ce procéder puisqu'il est fort utile dans ce genre de cas. On peut trouver pas mal d'exemple et d'explication sur le net.
jeudi 23 juillet 2015
Nebulla - level 12
Bonjour,
Ce niveau est pour
le coup très simple on va voir ca avec ce qu'on nous demande dans un
premier temps :
There is a backdoor process listening on port 50001.
To do this level, log in as the level12 account with the password level12. Files for this level can be found in /home/flag12.
Donc on apprend
qu'une backdoor tourne sur le port 50001 avec le script indiqué
coder en lua :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 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 |
On va simplement
lancer netcat dans le but de se connecter à cette backdoor et voir
ce qu'elle fait.
Sans savoir
programmer du tout en lua on peut comprendre assez simplement qu'un
password est demandé. Ce password alors passe par une fonction
hacher notre mot de passe via une fonction system. Le soucis vient
ici du fait que la fonction va utiliser notre password sans faire de
checking pour savoir ce que je vais lui envoyer donc il suffit
simplement que je lui envoie un password avec une commande du système
(la commande sera séparé du password par un simple ; (note je
pourrais aussi utiliser |) et j'aurais fait mon job. Ça ressemble a
un niveau précédent :
Rien de bien
compliqué comme vous pouvez le voir.
Nebulla - level 11
Bonjour,
Voici le niveau 11
donc voici ce que l'on nous donne :
The /home/flag11/flag11 binary processes standard input and executes a shell command.
There are two ways of completing this level, you may wish to do both :-)
To do this level, log in as the level11 account with the password level11. Files for this level can be found in /home/flag11.
À la différence
des autres niveaux ici on nous encourage à faire ce niveau avec les
2 possibilités donc nous allons faire ce qu'ils nous demandent ! Voici la source :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <fcntl.h> #include <stdio.h> #include <sys/mman.h> /* * Return a random, non predictable file, and return the file descriptor for it. */ int getrand(char **path) { char *tmp; int pid; int fd; srandom(time(NULL)); tmp = getenv("TEMP"); pid = getpid(); asprintf(path, "%s/%d.%c%c%c%c%c%c", tmp, pid, 'A' + (random() % 26), '0' + (random() % 10), 'a' + (random() % 26), 'A' + (random() % 26), '0' + (random() % 10), 'a' + (random() % 26)); fd = open(*path, O_CREAT|O_RDWR, 0600); unlink(*path); return fd; } void process(char *buffer, int length) { unsigned int key; int i; key = length & 0xff; for(i = 0; i < length; i++) { buffer[i] ^= key; key -= buffer[i]; } system(buffer); } #define CL "Content-Length: " int main(int argc, char **argv) { char line[256]; char buf[1024]; char *mem; int length; int fd; char *path; if(fgets(line, sizeof(line), stdin) == NULL) { errx(1, "reading from stdin"); } if(strncmp(line, CL, strlen(CL)) != 0) { errx(1, "invalid header"); } length = atoi(line + strlen(CL)); if(length < sizeof(buf)) { if(fread(buf, length, 1, stdin) != length) { err(1, "fread length"); } process(buf, length); } else { int blue = length; int pink; fd = getrand(&path); while(blue > 0) { printf("blue = %d, length = %d, ", blue, length); pink = fread(buf, 1, sizeof(buf), stdin); printf("pink = %d\n", pink); if(pink <= 0) { err(1, "fread fail(blue = %d, length = %d)", blue, length); } write(fd, buf, pink); blue -= pink; } mem = mmap(NULL, length, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); if(mem == MAP_FAILED) { err(1, "mmap"); } process(mem, length); } } |
Donc dans un premier
temps on peut voir que le programme sera assez basique ici une simple
série de test pour (si ceux-ci n'ont pas fail) utiliser la fonction
system sur le buffer utilisé dans la fonction process. La commande
envoyé dans le buffer va passer par un algorithme basique appelé
simplement `Stream cipher` (généralement utilisé dans l’encryption de flux de donné) avec un petit xor. Ce sera utile pour la
suite. Voici un test basique pour voir que le programme fonctionne
bien :
La première manière
de faire ici sera de prendre ce petit programme et de rechercher
l'algorithme
utilisé pour encrypter notre string à l'envers de l’algorithme
donné. Il se situe simplement avant le lancement de la fonction
system :
key = length & 0xff; for(i = 0; i < length; i++) { buffer[i] ^= key; key -= buffer[i]; }
Donc on va devoir
connaître la taille de notre commande ainsi que la commande en elle
même jusque là on aura pas de soucis. On doit faire en sorte que la
commande ne de dépasse pas 1024 bytes ici sinon le checking de fread
va nous empêcher d'avancer. La commande au passage ne doit pas se
terminer par un caractère nul comme normalement. Donc on va dans un
premier temps encoder notre commande et simplement l'afficher dans un
programme basique. Je vais coder un exemple en C et un autre en
python mais le résultat sera identique dans tout les cas :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | #include <stdlib.h> #include <stdio.h> #include <string.h> void process(char *buff, int length){ unsigned int key; int i; i = 0; key = length & 0xff; while (i < length) { buff[i] ^= key; key -= buff[i] ^ key; i++; } } int main(void){ char buffer[1024]; strncpy(buffer, "getflag", 1024); process(buffer, 1024); puts("Content-Length: 1024"); fwrite(buffer, 1, 1024, stdout); return 0; } |
Voici donc le second
code en python :
1 2 3 4 5 6 7 8 9 10 11 12 13 | #!/usr/bin/env python cmd = "getflag\x00" size= 1024 key = size & 0xff encrypted = "" for i in range(len(cmd)): enc = (ord(cmd[i]) ^ key) & 0xff; encrypted += chr(enc) key = (key - ord(cmd[i])) & 0xff print "Content-Length: " + str(size) + "\n" + encrypted + "A"*(size - len(encrypted)) |
Voici donc le
résultat la commande est bien exécuté le soucis vient ici
uniquement du programme en lui même puisque lorsque le call de
system est fait il n'y a pas de seting d'uid donc il va logiquement
utilisé celui de lanceur de l'action qui ne sera logiquement pas le
flag ici mais le level il aurait fallut utiliser donc les fonctions
setresuid/setresgi
pour
résoudre ce soucis. J'ai set la variable d'environement TEMP vers /tmp pour ne plus avoir le message d'erreur dût au fd créer en mode random.
La seconde façon de
faire sera de jouer simplement avec LD_PRELOAD ainsi que les
fonctions que l'on va pouvoir alors override.. Je vous laisser chercher
à ce niveau ce sera pas bien compliqué !
Nebulla - level 10
Bonjour,
On commence à
entrer dans des niveaux où le fun arrive. A partir de ce niveau la
compréhension du code C est obligatoire. Vous pouvez bien entendu
tenter de comprendre ma solution mais je vous encourage vivement si
vous êtes perdu à simplement vous documentez (ou a posez vos
questions). L'ip que je vais utiliser sera bien entendu mon ip local ici (192.168.1.43)Je vais tenter d'expliquer au mieux de la manière la
plus simple (à mes yeux) tout en étant technique. Voici ce que l'on
nous demande ici :
The setuid binary at /home/flag10/flag10 binary will upload any file given, as long as it meets the requirements of the access() system call.
To do this level, log in as the level10 account with the password level10. Files for this level can be found in /home/flag10.
On nous donne aussi
un fichier source C plutôt évolué ici sans forcement être
compliqué pour autant :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | #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); } } |
Nous avons aussi un
fichier token disponible dans la racine du flag de disponible mais
sans droit en lecture :
On voit que le
programme va demander deux arguments ici un fichier un host pour se
connecter (sur le port 18211). Ensuite un test pour se connecter à
l'host puis si connecter une écriture sur le fd (qui est le socket
de l'host donné en paramètre donc). Une fois tout ça passé le
contenu du fichier passé en paramètre sera alors read puis write sur
le fd du socket donc. Et enfin un petit message pour dire que tout
est bon.
Le programme est pas
bien compliqué le seul soucis ici sera lié au moment de lancer les deux
lignes suivante :
if(access(argv[1], R_OK) == 0 ffd = open(file, O_RDONLY);
En effet par le man
on peut comprendre simplement qu'il y a un gros soucis ici je cite
donc :
Utiliser access pour vérifier si un utilisateur a le droit, par exemple, d'ouvrir un fichier avant d'effectuer réellement l'ouverture avec open(2), risque de créer un trou de sécurité. En effet, l'utilisateur peut exploiter le petit intervalle de temps entre la vérification et l'accès pour modifier le fichier (via un lien symbolique en général).
On est exposé ici à
une faille relativement connu du simple nom de TOCTOU qui va
implicitement nous faire utiliser le principe du race condition.
Sachant que nous
sommes ici dans un cas bien réel de race condition ainsi que dans
une utilisation d'un programme qui va se connecter en réseau nous
allons devoir utiliser netcat qui va nous faciliter la tâche je vous
invite à tenter de comprendre de ce logiciel qui est indispensable à
comprendre. Je vais utiliser un
peu de shell basique histoire de simplement gagner du temps.Voici un test
basique pour voir que tout fonctionne bien dans des fichiers sans
restriction :
Donc voila le
résultat du premier test basique avec un fichier dont on a les
droits maintenant avec un fichier sans droit :
Maintenant nous
allons dans l'ordre créer un link forcer (via -f) depuis notre
fichier token vide vers un fichier link token donc et nous allons
link le fichier token sur lequel nous n'avons aucun droit vers ce
même link le tout en boucle infini. Pour ça je vais utiliser une
commande assez basique :
Nous allons ensuite
lancer un client netcat en mode serveur en boucle en ayant une redirection sur sa sortie vers un fichier (ici du nom de out) :
Et enfin voici le
programme lancé lui aussi en boucle infini avec le fichier relink en
boucle :
Après quelques
seconde une simple lecture du fichier out va nous donner le contenu
du fichier token.
Il suffit alors
d'utiliser le mot de passe que l'on a pour récupérer notre flag !
mercredi 22 juillet 2015
Nebulla - level 09
Bonjour,
Nous allons
aujourd'hui voir un niveau un peu plus complexe qui va demandé
d'avoir des notions de PHP. Donc avant tout je vous conseil
d'apprendre à comprendre au minimum les bases puisqu'elles seront
utile ici.
Voyons ce qu'il faut
faire ici :
There’s a C setuid wrapper for some vulnerable PHP code…
To do this level, log in as the level09 account with the password level09. Files for this level can be found in /home/flag09.
On voit devoir donc
comprendre le code PHP qui nous est donné ici :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <?php function spam($email) { $email = preg_replace("/\./", " dot ", $email); $email = preg_replace("/@/", " AT ", $email); return $email; } function markup($filename, $use_me) { $contents = file_get_contents($filename); $contents = preg_replace("/(\[email (.*)\])/e", "spam(\"\\2\")", $contents); $contents = preg_replace("/\[/", "<", $contents); $contents = preg_replace("/\]/", ">", $contents); return $contents; } $output = markup($argv[1], $argv[2]); print $output; ?> |
Le premier truc que
l'on peut remarquer est l'utilisation de deux fonctions. La première
fonction sera appelé par la seconde qui elle même sera appelé par
les arguments passé au lancement du script . On faire un
listing voir s'il y a un truc qu'on aurait pu ne pas voir :
Donc rien de magique
ici à faire tout est indiqué. On va donc devoir trouver une manière
d'exploiter le programme normalement. On va pour le moment
simplement lancer le programme pour voir s'il fait ce qu'on pense :
Rien de bien farfelu
on va donc tenter de comprendre ce qui n'est pas normal dans le code
que l'on pourrait exploiter. Nous allons regarder une ligne en
particulier puisqu'il s’agit simplement de la ligne qui va call la
première fonction de notre script :
$contents = preg_replace("/(\[email (.*)\])/e", "spam(\"\\2\")", $contents);
Avec un peu
d’expérience on peut penser à une faille XSS le soucis simple ici
c'est qu'on ne peut et surtout ne doit pas utiliser de javascript. On
va donc utiliser ce principe pour pouvoir exécuter la fonction que
l'on souhaite On peut voir qu'il existe une fonction system qui
risque de nous être utile pour notre exploitation. On va donc avoir
besoin ici de notre fichier contenant notre script qui va modifier
simplement l’exécution du script en notre faveur. Ce qu'il faut
penser ici ( et c'est en réalité le seul soucis) ce sera d'escape
les valeurs situé dans notre fichier pour que celle-ci soient bien
interprété. Je ne vais pas vous montrer le nombre de test que j'ai
fais puisque pour le coup ce sera mieux pour voir que vous les
fassiez dans votre coin (par exemple la premier test sera d'afficher
un simple phpinfo()). Je vais simplement vous montrer ma manière de
résoudre ce niveau assez simplement :
Donc j'ai simplement
utilisé la fonction system qui permet d’exécuter une commande du
système et je lui ai donné pour argument la second variable que je
passe dans le lancement du programme. Je peux donc par la suite
exécuter la commande de mon choix (ici un shell) et faire ce que
j'ai besoin. Le reste ne sera simplement que dans le but de rendre le
code lisible par PHP (donc de l'escape).
Ce niveau peut
sembler étrange pour les personnes n'ayant pas forcément de bonne
notion en PHP et pour celle-ci je conseil vivement de se mettre à
jour puisque vous allez vite le remarquer mais lorsque l'on va
vouloir exploiter dans le web en général le PHP sera un pré-requis
au minimum pour la compréhension du fonctionnement du langage
mardi 21 juillet 2015
Nebulla - level 08
Bonjour,
Nous allons voir
maintenant ce niveau 8. Vous aurez besoin d'utiliser quelques outils
mais nous allons dans un premier temps voyons voir ce qu'on nous
demande !
Pas grand-chose donc
je vais donc tenter de me log pour faire un listing si on peut avoir
une petit idée.
On peut voir un
fichier ayant une extension particulière ici. Après quelques
recherche sur google on peut voir qu'il s’agit en réalité d'un
fichier ayant en contenu une simple trame de réseau. Une liste de
packet qu'on va devoir tenter de comprendre (avoir des notions en
protocole tcp/ip peut être utile ici).
Je vais utiliser le
logiciel Wireshark pour traiter ce fichier spécifique mais pour ça
je vais avoir besoin du fichier en question et pour récupérer
celui-ci je vais utiliser un autre petit logiciel qui permet de faire
du transfert de fichier depuis un serveur ssh nommé `scp`. Je vous
encourage à comprendre son fonctionnement.
Voilà le fichier
étant sur notre disque nous pouvons l'ouvrir maintenant via
Wireshark. A partir d'ici je vais aller un peu plus rapidement et
donc si vous souhaiter apprendre à utiliser ce logiciel de façon
plus complète il faudra le faire de votre coté.
Une fonction bien
sympathique dans ce logiciel permet de voir la communication entre
deux clients (dans la trame donné) en raw (c'est à dire sans
encodage ou autre juste lisible en 'plain text').
Pour ça un simple
clique droit sur un packet de notre choix suffit (il faudra choisir
dans le menu l'option Follow TCP Stream). Voici ce que vous devriez
voir :
J'ai choisis
l'affichage hexadécimal puisque ca va nous permettre de voir les
actions qui ont pu avoir été faite dans un format lisible.En
cherchant un petit peu on peut trouver un truc qui semble un petit
plus intéressant:
On peut voir assez
clairement le password mais une chose est étrange ici des caractères
lisibles mais à un moment précis on voit une coupure ce qui n'est
pas vraiment normal. Pas mal d'entre vous ont sûrement vu des
caractères étrange á gauche de chaque caractère lisible la
liaison pour le coup est assez simple puisqu'en réalité il s'agit
simplement de la représentation ascii. Lorsque l'on regarde via une
table sur le net on peut voir que le caractère hexadécimal 7F est
simplement un simple DEL qui n'est rien d'autre qu'un backspace qui
permet d'effacer le caractère précédent.
La suite logique
revient à prendre ce password (`backd00Rmate`) et l'utiliser pour
récupérer le flag en se connectant en ssh grâce à celui-ci :
Ce niveau était
plutôt sympa on a pu simplement trouver un password dans un fichier
contenant une trame réseau. On pourrait très bien avoir un
équivalant de ce fichier en live via du sniffing basique. En
réalité ce ne serais pas si simple puisque le réseau utilise
souvent des données qui seront crypté (par SSL par exemple). On
peut comprendre maintenant l'importance de SSL en général (même si
on a vu que très peu de chose pour le moment).
Si vous avez des
questions il ne faut pas avoir peur de demander puisque les choses
vont devenir petit à petit de plus en plus compliquer.
Inscription à :
Articles (Atom)