Daddy told me about cool MD5 hash collision today. I wanna do something like that too!
ssh col@pwnable.kr -p2222 (pw:guest)
Code Review
#include<stdio.h>#include<string.h>unsignedlong hashcode =0x21DD09EC;unsignedlongcheck_password(constchar* p){int* ip = (int*)p;int i;int res=0;for(i=0; i<5; i++){ res += ip[i]; }return res;}intmain(int argc,char* argv[]){if(argc<2){printf("usage : %s [passcode]\n", argv[0]);return0; }if(strlen(argv[1])!=20){printf("passcode length should be 20 bytes\n");return0; }if(hashcode ==check_password( argv[1] )){system("/bin/cat flag");return0; }elseprintf("wrong passcode.\n");return0;}
The program takes 5 4-byte hex numbers as argv[1] and it calls check_password(). If the sum of these 5 hex numbers equals 0x21DD09EC then the program prints out the flag.
Solution
We need to find 5 integers in hex that sum to 0x21dd09ec. The naive idea is to divide 0x21dd09ec by 5. It won't work because 0x21dd09ec isn't divisible by 5. But, following from this logic, we could find a solution using the formula:
0x21dd09ec = (0x21dd09ec // 5) * 4 + <residue>
Here we have 0x21dd09ec // 5 = 0x6c5cec8, so residue = 0x21dd09ec - 0x6c5cec8 * 4 = 0x6c5cecc. Since the convertion is done by int* ip = (int*)p (pointer, not string), we should use little-endian in argv[1].
Exploit
#!/usr/bin/env python3# -*- coding: utf-8 -*-# This exploit template was generated via:# $ pwn template --host pwnable.kr --port 2222 --user col --password guest --path /home/col/colfrom pwn import*# Set up pwntools for the correct architectureexe = context.binary =ELF('col')# Many built-in settings can be controlled on the command-line and show up# in "args". For example, to dump all data sent/received, and disable ASLR# for all created processes...# ./exploit.py DEBUG NOASLR# ./exploit.py GDB HOST=example.com PORT=4141host = args.HOST or'pwnable.kr'port =int(args.PORT or2222)user = args.USER or'col'password = args.PASSWORD or'guest'remote_path ='/home/col/col'# Connect to the remote SSH servershell =Noneifnot args.LOCAL: shell =ssh(user, host, port, password) shell.set_working_directory(symlink=True)defstart_local(argv=[],*a,**kw):'''Execute the target binary locally'''if args.GDB:return gdb.debug([exe.path] + argv, gdbscript=gdbscript, *a, **kw)else:returnprocess([exe.path] + argv, *a, **kw)defstart_remote(argv=[],*a,**kw):'''Execute the target binary on the remote host'''if args.GDB:return gdb.debug([remote_path] + argv, gdbscript=gdbscript, ssh=shell, *a, **kw)else:return shell.process([remote_path] + argv, *a, **kw)defstart(argv=[],*a,**kw):'''Start the exploit against the target.'''if args.LOCAL:returnstart_local(argv, *a, **kw)else:returnstart_remote(argv, *a, **kw)# Specify your GDB script here for debugging# GDB will be launched if the exploit is run via e.g.# ./exploit.py GDBgdbscript ='''tbreak maincontinue'''.format(**locals())#===========================================================# EXPLOIT GOES HERE#===========================================================# Arch: i386-32-little# RELRO: Partial RELRO# Stack: Canary found# NX: NX enabled# PIE: No PIE (0x8048000)argv = [p32(0x6c5cec8)*4+p32(0x6c5cecc)]print(f"{argv = }")io =start(argv)success(io.readall().decode())