to my homepageview my exploit code (requires libjh)
In this challenge, you have to exploit a server that allows you to download and
upload files. The goal is to retrieve /home/sftp/flag, but the server
blocks every filename that contains flag. And you can't move, rename,
overwrite, ... that file because your user only has read access:

And you can retrieve them (and files from anywhere else on the system as long as you have access and the name isn't blacklisted):

RETR /home/sftp/incoming/test123
11SEND
hello world

Finally, you can also delete files – useful for cleaning up after running your exploit:

KILL /home/sftp/incoming/test123
+/home/sftp/incoming/test123 deleted

So how can you exploit this? Have a look at that RETR command again – there is really no
reason why you'd need to confirm that you really want that file, right?Edit: There is
a reason, see RFC 913 - a client might
not have enough free space to store the file. Thanks to gynophage for pointing that out.
And this is where the vuln hides. The loop from 0x08049415 to
0x08049468 reads the file byte by byte into a buffer with the file's size
that was allocated on the stack earlier, but this loop reads the entire file, not just
the number of bytes it expects. Therefore, you can overflow the buffer by using two
connections: You store an empty file over connection 2, send RETR over
connection 1, append data to the file over connection 2 and send SEND over
connection 1. Then, the buffer will only be big enough for an empty file and all the
stuff in the file will be written over the stack.
However, exploiting the vuln needs some more work. For an initially empty file, the
stackframe looks like this (relative to ebp):

So there's a canary in the way that you must not modify, and to make things even worse, behind the buffer-pointer is the
FILE* that's in use – if you overwrite that, the program will crash.
The trick is: In front of all the stuff you aren't allowed to touch, there is the index into the buffer. Because you can only write one
byte at a time, you can only modify one of the bytes in the index though, so you can't modify the index so that you jump between
the canary and the stored return pointer. However, you can increment it by 0x400 or so and then stop writing – that won't
write anything behind the counter, but it will cause 0x400 bytes from behind the counter to be seen as part of the buffer
when the buffer is sent to you. Therefore, this lets you leak the stack including the canary value.
After you have grabbed the stack, you need to modify the stored return pointer and the space behind it to call a function of your
choice with arguments of your choice. Also, when you attack the server with the new crafted stack, you have to keep in mind that
the FILE* will be different this time, so you have to jump over a little bit of space behind the counter. For that, you
overwrite the first byte of the counter with 0xff.
Now what method do you choose to call? You could try to repurpose the file-reading code in the binary to read the flag, but at least
I think that if you can already overwrite stuff on the stack, you should aim for
system() with an arbitrary string as argument. ASLR is on, and you can't read
/proc/self/maps because that file seems to have zero size in procfs and therefore crashes the server when you try to read it.
However, there is some pointer into the libc on the stack (at ebp+0x138), and by first dumping the stack and then reading
/proc/self/maps once (it only crashes after it has dumped the maps data), you can find out which constant you need to subtract
to find out where the libc starts in memory.
One thing to note about my exploit is that it doesn't work for commands that are too long for some reason – it's enough for
cat ../flag though, and it's also enough for doing chmod +x aa and then ./aa to run an arbitrary
uploaded file.
If you have comments/questions, feel free to ask me, either by email (consisting of jann, an @ sign and the domain this website is on)
or on IRC (TheJH on freenode) – but for questions, please check whether my exploit answers them first.