$\mathrm{Enc}_k$ always transforms the same block value to the same block value. Since blocks are only one byte long, there are only 256 different block values. So you can build a table of those from the parts of the plaintext that you know. Once you've built that table, you can use it in the reverse direction to calculate $\mathrm{Dec}_k$.
$$
\begin{array}{l|l}
x & \mathrm{Enc}_k(x) \\ \hline
0 & \_ \\
1 & \_ \\
\vdots \\
255 & \_ \\
\end{array}
$$
Knowing $M_1$, the equation $C_1 = \mathrm{Enc}_k(M_1 \oplus C_0)$ gives you one entry in the table. More generally, whenever you know the value $M_i$, the equation $C_{i+1} = \mathrm{Enc}_k(M_{i+1} \oplus C_i)$ gives you one entry in the table. Some positions may call $\mathrm{Enc}_k$ on the same input as another position, so it may take more than 256 known bytes in the plaintext, but with a few hundred bytes of known plaintext the probability of missing entries decreases rapidly¹ since the inputs for different values of $i$ are essentially random.
If there are missing values in the table, you can narrow things down in two ways. First, since $\mathrm{Enc}_k$ is a permutation, all the values in the second column are distinct. Second, all the $M_i$ are probably printable characters, which limits the possibilities. Within the scope of the exercise, I'd expect that if there are any blanks, they're easy to fill in with a little hand-driven calculation.
The core of the problem is the 8-bit block. An 8-bit block is far, far too short. In the real world, older block ciphers such as DES and ((X)X)TEA have 64-bit blocks, and modern block ciphers have 128-bit blocks. Even with a 64-bit block, such a table attack is unlikely to give any useful results (the table would require 128 EiB of sttorage, and you'd need roughly that amount of guessable plaintext with a known ciphertext to build it). 64-bit blocks are vulnerable to a sparse version of this attack where you hope that $\mathrm{Enc}_k$ has been called twice on the same input, and this reveals something about the message (if $C_i = C_j$ then $M_i \oplus C_{i-1} = M_j \oplus C_{j-1}$, which reveals the value of $M_i \oplus M_j$, and in particular reveals $M_j$ if you know $M_i$). And you only need about $2^{32}$ blocks of message to have a decent chance of a repeated block value (birthday bound), which makes this attack practical (most famously as Sweet32).
CBC itself with a block cipher with a decent-size block and with a random IV is secure even against chosen-plaintext attacks (IND-CPA). However, it is not at all secure against adaptative chosen-plaintext attacks, where the attacker can submit some plaintext to encrypt after seeing the previous portion of the ciphertext.
In the adaptative case, I know $C_i$ and am allowed to submit $M_{i+1}$ which lets me learn $C_{i+1} = \mathrm{Enc}_k(M_{i+1} \oplus C_i)$. So I choose $M_{i+1} = C_i \oplus x$ and this way I can learn $\mathrm{Enc}_k(x)$ for an arbitrary $x$. If I've guessed a plausible value for $M_j$ for some $j$, this lets me verify this guess by testing whether $C_{i+1} = C_j$.
CBC as used in practice is not secure in general because it requires padding, since CBC can only encrypt a whole number of blocks. Padding is vulnerable to padding oracle attacks in scenarios where the attacker can submit chosen ciphertext. This is why CBC is deprecated, especially for communication. (It can be ok for storage where the adversary might be able to see ciphertext, e.g. from leaked backups, but has no way to inject ciphertext.)
¹ Unless $\mathrm{Enc}_k$ has some correlation with $M$.