Aujourd'hui on s'attaque au challenge "input" de pwnable.kr. Disponible ici.

Le code est composé de 6 parties. A chaque étape validée un message nous en informe.
NB: Je me suis permis de rajouter des printf() afin de rendre le code plus clair.

Partie 1: Utilisation de argV
Partie 2: Utilisation de stdio
Partie 3: Utilisation des variables d'environnement
Partie 4: utilisation des fichiers
Partie 5: Utilisation des sockets
Partie 6: le GRALL

Comme le challenge est découpé en étapes, on va le résoudre une étape après l'autre.

Etape 1: ArgV

Partie 1: Utilisation de argV

Dans cette étape il faut:

  • Fournir 100 arguments
  • Que l'argument 'A' soit de valeur nulle
  • Que l'argument 'B' ait la valeur \x20\x0a\x0d

Avant tout il faut comprendre ce que veut dire la formulation argv['A']? C'est assez simple en fait. Ecrit comme ça le A est transformé en sa valeur ASCII pour être utilisé comme indice du tableau argv. On peut donc traduire cette ligne par argv[65]. Même principe pour le argv['B'] qui devientargv[66].

Pour passer cette première étape, je pourrai me contenter de faire un one-liner en python. Mais vu le nombre d'étapes il va très vite devenir illisible. Je vais plutôt faire un script python2 que je vais compléter au fur et à mesure.

Voici de quoi passer le premier stage:

#!/usr/bin/env python
#-*- coding utf-8 -*-

from pprint import pprint

import os
import sys
import subprocess

myArgs = ["0"]*99
myArgs[ord('A')-1] = "" #"\x00" # In python you can't passe null value but empty value do the job
myArgs[ord('B')-1] = "\x20\x0a\x0d"

subprocess.Popen(['./input'] + myArgs)

Etape 2: StdIO

Partie 2: Utilisation de stdio

Pour cette seconde partie, il faut rediriger pipes d'entrée standard et d'erreur standard. Pour ça on va utiliser la fonction pipe() fournir par le module os.

https://www.tutorialspoint.com/python/os_pipe.htm

Pour écrire les données qui nous intéressent ont va utiliser la fonction write() du module os.

Voilà la version pour valider jusqu'à l'étape 2.
Et voila !

Etape 3: Env

Partie 3: Utilisation des variables d'environnement

Pour cette partie, il faut créer une variable d'environnement qui porte le doux nom de \xde\xad\xbe\xef et contient la valeur \xca\xfe\xba\be.

Concentrons nous sur la fonction qui nous intéresse ici: getEnv

https://koor.fr/C/cstdlib/getenv.wp

Si l'on se réfère à la documentation de python.

https://docs.python.org/fr/3/library/subprocess.html
https://docs.python.org/fr/3/library/subprocess.html

Voila qui nous arrange bien ! On créé donc le fameux tableau associatif.

Un tableau associatif en python
Voila de quoi valider jusqu'à l'étape 3

Etape 4: File

Partie 4: utilisation des fichiers

Cette fois-ci il faut créer un fichier nommé 0x0A et le remplir avec 4 nulls bytes.

Une simple formalité !
Voila de quoi valider jusqu'à l'étape 4

Etape 5: Socket

Partie 5: Utilisation du réseaux

Pour cette étape, il faut crée un socket qui va se connecter sur le port contenu dans argv['C'] et qui envoyer la valeur \xde\xad\xbe\xef quand on s'y connecte. Là encore rien de très compliqué.

Voila de quoi valider l'étape 5

Etape 6: Le flag

Maintenant que notre programme tourne en local, il ne reste plus qu'a l'uploader sur la machine de pwnable.kr.

Si je lance le programme, il ne peut pas trouver le fichier flag car il n'est pas dans le répertoire que j'ai créé (/tmp/AgsWasHere ), et je ne peux pas l'y mettre car je n'ai pas les droits.

Cependant, on peut créer un lien symbolique en utilisant ln -sf.
Et voila !

NB: Il ne faut pas oublier d'adapter le chemin du fichier input pour le remplacer par un chemin absolu et valable sur la machine pwnable.kr

NB,NB: J'aurais bien aimé utilisé pwntools pour ce challenge mais le problème est qu'il ne fonctionne qu'en 64 bits...

Voici le code complet

#!/usr/bin/env python
#-*- coding utf-8 -*-

from pprint import pprint

import os
import subprocess
import socket
import time
import random

port = random.randrange(10000, 20000)

# Step 1
myArgs = ["0"]*99
myArgs[ord('A')-1] = "" #"\x00" # In python you can't passe null value but empty value do the job
myArgs[ord('B')-1] = "\x20\x0a\x0d"
myArgs[ord('C')-1] = str(port)

# Step 2
stdinr, stdinw = os.pipe()
stderrr, stderrw = os.pipe()
os.write(stdinw,  "\x00\x0a\x00\xff")
os.write(stderrw, "\x00\x0a\x02\xff")

# Step 3
with open("\x0a", "a") as f: f.write("\x00\x00\x00\x00")

# Step 4
env_var = {"\xde\xad\xbe\xef" : "\xca\xfe\xba\xbe"}

subprocess.Popen(['./input'] + myArgs, stdin=stdinr, stderr=stderrr, env=env_var)

# Step 5
time.sleep(1) # Needed else not possible to connect socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("127.0.0.1", port))
s.send("\xde\xad\xbe\xef")
s.close()

Social et Media

Comme toujours je suis disponible sur Twitter et cie, si vous avez des questions, des remarques, des suggestions etc. N’hésitez pas !

Twitter: @GhostAgs

Discord: hackraw