zer0pts CTF 2021
crypto
pwn
We're given the target binary and the source codes.
The program implements an RSA (CRT) signature.
We can sign an arbitrary message padded by PKCS1 v1.5 and after that we have to sign a given message.
Basically it's impossible to break the signature because public key is 2048-bit, which is too big to factorize.
In get_message
function it allocates a buffer named msg
for storing our input, then pad the message and finally free all buffers.
This doesn't look bad but the vulnerability lies in pad_pkcs1_v15
function.
Inside this function reallocates msg
at [2]. The size for this re-allocation is calculated at [1]. However, we can make it zero by giving 1021 as s
because n
is 1024.
This is possible as s
is decided by the size of the buffer, which relies on our input length.
If rlen
becomes zero, realloc
frees msg
in it at [2]. Even though msg
is freed here, it will be double-freed at [0].
Although there are some lines in which msg
is used after free such as [3-a] and [3-b], they will never be a problem.
First, the control won't reach [3-a] because the for
loop won't iterate when rlen
is zero.
Second, [3-b] will be executed but memcpy
won't crash when size is zero even if the source address is invalid.
So, we get a double free in the function.
The size of the chunk is SECURITY_PARAMETER / 8
, which is 0x80.
Let's check what happens when we cause the double free.
As these freed chunks are linked to tcache, it will affect chunks with size between 0x79 and 0x88.
The integer values created by gmp are allocated on the heap. Each chunk size is decided by the bit length of the integer.
In generate_signature
function, there are three 1024-bit integers allocated on the heap. These values use 0x80-byte chunk respectively because 1024/8=0x80.
Thus, it will cause chunk overlap. Precisely the buffers for sp
and qi
overlap. As a result, the value of sp
is overwritten by the value of qi
later.
The signature should be calculated by the following formula:
If the double free happens, however, the signature is calculated by the following formula:
Remember that .
Then, what does calculate?
Let be the difference between and :
can be written in the following way:
Let be for simplicity:
By binomial theorem, can be written as
where is an integer.
Now you may notice that can be denoted as for an integer .
This is a transformed form of Bellcore Attack.
As we have , we can find by the following formula:
After we successfully find , it's easy to sign any messages.