Unfortunately, we will not be directly selling these shirts, but I have another post tutorial on how to reproduce the shirt if you want to put in the bit of extra work to get one.
Regex (bug-bounty style vulnerability)
We've covered this vulnerability multiple times on the podcast and it was our Spot the Vuln on Episode 152 (written in Golang).
The regex in
allow. It looks normal, and if you test it in the obvious ways it seems to work.
api.notsafe.com fails. Because it matches the start of the string with
^ and ends with a
/ you can't just append data to the end like
https://api.safe.com.notsafe.com. So it defends against some common issues.
The problem is that in regex
. is a wildcard character. It'll match with any character at all, not just a
. character. An attacker could register a domain like
api-safe.com and the
. will match the
- character without complaint.
Its a somewhat common issue as far as regex problems go simply because it looks correct for a domain, so at a glance its easy to think it is correct. The context of this code is not known, but its easy to imagine a scenario where this would lead to a SSRF.
Just be Positive (memory corruption vulnerability)
This is an old spot the vuln, based on one that can be found in the 2006 book Art of Software Security Assessment. We have used it a couple times on the podcast, most recently on Episode 196.
length = length * -1 doesn't work with
INT_MIN * -1 == INT_MIN) becuse of a side-effect of how signed integers work. This means the attempt to correct the data is effectively a no-op, and the bounds check passes because
INT_MIN is certainly smaller than
read is eventually called, the
length is converted to an
unsigned int resulting in a far too large write into
buf and a stack-based overflow.
Going a bit deeper for those unfamiliar, lets lay out what the code is doing. The idea is you have this
read_data function which reads data from a socket file descriptor and processes that data and eventually returns a
char * containing it after some other processing. After allocating a stack buffer to contain the raw packet data. It reads the first
int from the packet into
length which is going to represent the length of the data to read. It does some checks on the
length value. First ensuring the value is always positive by multiplying any negative length by
-1 to turn it into a positive value. Then checking that the length is not longer than the allocated buffer. Finally it reads
length bytes into the buffer.
The problem stems from trying to correct the user input rather than rejecting it. This bit of code:
length = length * -1 is the problem.
Mathematically this will work, for every value when multiplied by
-1 it will flip the sign of the value. This doesn't hold true in a digital sense for most CPUs because of something called Two's Compliment which is how the CPU stores values that can be negative or positive. I won't go into all the details about how this work, but it means that signed integer types don't have an equal range of positive and negative values. For exmaple, a one-byte value in two's complient has a range of
127, this is a consequence of how two's compliment works. With a one-byte value, if you try to multiple
-1, what you should get is
128 but the upper most bit of that gets truncated because it can't fit inside of a single byte. Resulting, rather unintuitively in
-128 * -1 being
-128. This is true at all sizes of signed integers, the minimum value multiplied by
-1 will result in itself.
As such an attacker can provide a
length value in the packet of
INT_MIN the first
if condition will in effect be a no-op. The second
if condition doing the bounds check will see
-4billion something which is of course smaller than
MAX_PACKET and let it through. Then finally when
length is passed into the
read function it will implicitly be converted into an
unsigned int which will be a large value, 4 billion something. Resulting in
read copying in way more than
MAX_PACKET bytes into
buf giving you a stack-based linear overflow.