QuickScan
Catégorie: Reverse Difficulté: medium Flag: HTB{y0u_4n4lyz3d_th3_p4tt3ns!}
Challenge
Description
QuickScan is a Medium reversing challenge. Players will be sent a series of small, randomly generated ELF files and must rapidly and automatically anlalyse them in order to extract required data.
Ce challenge tourne sur un docker, disponible sur Github
Explications
On peut s’amuser à enregistrer 2-3 ELF que le serveur nous donne. On s’aperçoit rapidement d’un pattern : bien que la fonction entry
change de position à chaque fois, elle reste toujours la même dans ses instructions et l’adresse où se trouve les données attendues est mise dans RSI
grâce à l’instruction LEA
Ici les données attendues par le serveur sont à l’adresse 0x08048104

Ce qui est important c’est la valeur en vert dans l’instruction LEA
, il s’agit de l’offset utilisé pour trouver l’adresse de nos données. Ici c’est 0xfffffdb9
(on est en little endian) ce qui nous donne -583
(cette valeur est signée)
Actuellement le LEA
est à l’adresse 0x08048344
et la prochaine instruction est 7 bytes
plus loin, soit 0x0804834b
Donc si l’on fait 0x0804834b - 583
on tombe bien sur 0x08048104
, c’est à dire les données à récupérer.
En résumé, il faut :
Trouver l’adresse d’
entry
dans notre binaireRécupérer l’offset à
adresse(entry) + 7
Calculer
adresse(entry) + 11 + offset
Lire les
24 bytes
Script de résolution
from base64 import b64decode
from io import BytesIO
from struct import unpack
from elftools.elf.elffile import ELFFile
from pwnlib.tubes.remote import remote
def get_value(elf_content: bytes):
# On met les données sous forme de stream pour que elftools puisse le lire
with BytesIO(elf_content) as f:
elf = ELFFile(f)
# Adresse physique à laquelle le segment est chargé
base_address = elf.get_segment(0)['p_vaddr'] # 0**x08048000 dans notre exemple**
# Adresse d'entry du script
entry = elf.header['e_entry'] # **0x08048340 dans notre exemple**
# La différence des deux permet de trouver l'adresse dans le binaire
eip = entry - base_address # 0x340 dans notre exemple
# On a les bytes bytes sur SUB puis les 3 du LEA
eip += 4 + 3 # 0x347 dans notre exemple
# A partir de ça on peut lire l'adresse qu'utilise LEA directement dans le binaire
f.seek(eip)
data_offset = unpack('i', f.read(4))[0] # 0xfffffdb9 (-583) dans notre exemple
# Cet adresse est un offset qui dit à où aller à partir de d'EIP lui même
bin_addr = eip + 4 + data_offset # 0x347 + 4 + -583 = 0x104 (260) dans notre exemple
# Récupération des données
f.seek(bin_addr)
return f.read(0x18).hex()
def solve(host, port):
client = remote(host, port)
for i in range(128 + 1): # + 1, the first question doesn't count
client.recvuntil(b'ELF: ')
elf_content = b64decode(client.recvline())
answer = get_value(elf_content)
client.sendlineafter(b'Bytes? ', answer.encode())
flag = client.recvall(timeout=1).decode().split('flag: ')[1]
print(f"Flag: {flag}")
if __name__ == '__main__':
solve('localhost', 1337)
Dernière mise à jour
Cet article vous a-t-il été utile ?