Modèles de script

Certains défis exigent que vous interagissiez avec eux de manière interactive, voire programmative. Comme les communications avec les défis sont sécurisées grâce à SSL/TLS (pour que personne n'interfère avec votre trafic), vous aurez besoin des bonnes incantations. Les petits modèles de scripts suivants devraient vous aider à le faire sans trop de tracas. N'hésitez pas à consulter la référence de ces outils au besoin (RTFM comme on dit dans le jargon).

En ligne de commande

ncat (apt install ncat) possède une option --ssl. Cet outil peut être pratique pour expérimenter manuellement ce que le serveur raconte.

$ ncat --ssl jffi24-nathaniel.chals.hackin.ca 443

Même si ncat est interactif, c'est toutefois peu pratique de programmer avec.

socat (apt install socat) est plus sophistiqué et permet plus facilement la communication bidirectionnelle.

Pour l'équivalant interactif, on peut faire

$ socat SSL:jffi24-nathaniel.chals.hackin.ca:443 -

Si l'on veut "brancher" les entrées-sorties sur un programme, on peut faire

$ socat SSL:jffi24-nathaniel.chals.hackin.ca:443 EXEC:./mon_programme

Pour le programme, stdin et stdout sont correctement rédigés de et vers le serveur. stderr reste affiché sur la console. Merci socat!

Pour des constructions plus sophistiquées, il est plus simple et plus débogable de programmer la communication SSL/TLS directement dans le langage. Des bibliothèques existent pour la plupart des langages.

Python3 (pwntools)

#!/usr/bin/env python3
#
# https://docs.pwntools.com/en/stable/index.html
#
# tl;dr, pour installer les outils:
#
#   python3 -mvenv /tmp/venv-pwntools
#   . /tmp/venv-pwntools/bin/activate
#   pip install pwntools
#   python mon-script.py
#

from pwn import *

io = remote('chals.hackin.ca', 443, ssl=True, sni='lechall.chals.hackin.ca')

#io.recvline()          # lire 1 ligne
#io.recvuntil(b'hello') # lire jusqu'à la première occurence de b'world'
#io.sendline(b'world')  # envoyer b'world\n'
#io.send(b'world')      # envoyer b'world'
# plus encore... rtfm

# une connexion directe au socket
io.interactive()

Python3 (pure)

#!/usr/bin/env python3
#
# Une implémentation pure Python3 pour une connexion TCP sous TLS.
# On recommande fortement l'utilisation de la suite d'outils pwntools. :)
#

import contextlib
import socket
import ssl


@contextlib.contextmanager
def connexion(nom):
    ctx = ssl.create_default_context()
    ctx.check_hostname = False
    ctx.verify_mode = ssl.CERT_NONE

    try:
        with socket.create_connection(('chals.hackin.ca', 443)) as sk:
            with ctx.wrap_socket(sk, server_hostname=nom) as ssk:
              yield ssk
    finally:
        pass


# indiquer le nom de l'hôte pour le chall
with connexion('lechall.chals.hackin.ca') as io:
    # on tente de lire au maximum 4096 octets (et au moins 1)
    t = io.recv(4096)
    print(t)

    #io.send(b'Hello world!')

Ruby

#!/usr/bin/env ruby
#
# Une implémentation pure Ruby pour une connexion TCP sous TLS.
# On recommande fortement l'utilisation de la suite d'outils pwntools. :)
#

require 'openssl'
require 'socket'


def connexion(nom)
    ctx = OpenSSL::SSL::SSLContext.new
    sk  = TCPSocket.new 'chals.hackin.ca', 443
    ssk = OpenSSL::SSL::SSLSocket.new sk, ctx
    ssk.hostname = nom
    ssk.sync_close = true
    ssk.connect

    return ssk

end

io = connexion('lechall.chals.hackin.ca')

t = io.sysread 4096
puts t

#io.syswrite 'Hello world!'