Back to Blog

Reflexion über Reflexionstoken: Eine Sicherheitsbetrachtung

June 6, 2024

Aktualisiert am 14. Juni 2024: Ein Community-Mitglied hat diesen Blog sorgfältig geprüft und Informationen zu dem ADU-Vorfall bereitgestellt, der eine neue Form darstellt, die in unserer bisherigen Kategorisierung nicht abgedeckt ist. Danke, und jedes aufschlussreiche Feedback ist willkommen!

Zur Verbesserung der Marktstabilität werden Reflexionstoken (auch Belohnungstoken genannt) entwickelt, um Anlegern eine zusätzliche Möglichkeit zum Erwerb von Einkommen zu bieten. Dies ermutigt Anleger, ihre Token zu halten, anstatt sie zu handeln. Während der berüchtigten Meme-Coin-Saison 2021 wurden Reflexionstoken zu einem unverzichtbaren Mechanismus, der nach der Einführung auf Plattformen wie DxSale (z. B. SafeMoon V1) schnell die Aufmerksamkeit des Marktes auf sich zog.

Obwohl die Hektik nachließ und sich der Markt im Jahr 2023 abkühlte, hat unser System Dutzende von Tausenden von Hackerangriffen entdeckt, die solche Token-Mechanismen in der Praxis ausnutzen. Diese Reaper-artigen Angriffe führten, obwohl sie im Vergleich zu anderen Arten von DeFi-Angriffen relativ klein angelegt waren, zu nicht unerheblichen Verlusten von Nutzervermögen.

In diesem Blog konzentrieren wir uns hauptsächlich auf die Weitergabe von sicherheitsrelevanten Erkenntnissen aus unserer Forschung. Insbesondere geben wir zunächst eine kurze Einführung in den Mechanismus des Reflexionstokens. Danach werden wir Sicherheitsvorfälle im Zusammenhang mit Reflexionstoken überprüfen, mit Schwerpunkt auf denen, die den Mechanismus des Reflexionstokens ausnutzen. Anschließend werden wir ein potenzielles Sicherheitsproblem theoretisch diskutieren. Abschließend werden wir einige Gedanken zur Minderung und zu Lösungen teilen.

0x1 Mechanismus des Reflexionstokens

Nach unserem Kenntnisstand wurde dieser Mechanismus erstmals von Reflect Finance eingeführt, um einen Prozentsatz des Transaktionsbetrags als Gebühren nicht-transaktional an alle Token-Inhaber zu verteilen. Im März 2021 wurde die renommierte SafeMoon V1 auf der BNB-Kette veröffentlicht, was die Popularität des Reflexionstokens weiter steigerte.

0x1.1 Grundkonzepte

Bevor wir uns mit den Details befassen, sollten einige grundlegende Konzepte eingeführt werden, um ein besseres Verständnis zu erreichen.

Es gibt zwei Arten von Räumen: r-space und t-space, gesprochen reflektierter Raum und wahrer Raum. Die Krypto-Währungen der beiden Räume haben Wechselkurse, die auf dem relativen Umlaufvolumen basieren. Außerdem ist die Währung im r-space deflationär, d.h. für jede Transaktion wird ein bestimmter Prozentsatz verbrannt und infolgedessen wird der verbrannte Betrag vom Umlaufvolumen abgezogen.

Betrachten wir Alice, Bob und Eve, die beide Transaktionen in beiden Räumen durchführen können, wie in der folgenden Abbildung gezeigt. Wenn Alice und Bob paarweise Transaktionen im t-space durchführen, erhält Eve keine Belohnungen. Wenn jedoch alle drei zuerst ihre Token in den r-space umwandeln und dann Alice und Bob sich gegenseitig übertragen lassen, erhält Eve schließlich passive Einkünfte, indem sie ihre Token zurück in den t-space umwandelt. Das ist die Grundidee des Reflexionstoken-Mechanismus.

Beachten Sie, dass nicht alle Konten, wie z. B. der Liquiditätsbereitstellungspool des Tokens, in der Lage sind, im r-space zu handeln, d. h. bestimmte Konten müssen vom r-space ausgenommen werden.

0x1.2 Vertragsebene Erklärung

Nun wollen wir uns mit dem REFLECT-Vertrag von Reflect Finance befassen, um diesen Mechanismus zu erforschen.

Dieser Vertrag definiert zunächst mehrere Variablen für die Kontenverwaltung:

mapping (address => uint256) private _rOwned; // reflektierte Token, die vom Nutzer gehalten werden
mapping (address => uint256) private _tOwned; // wahre Token, die vom Nutzer gehalten werden
mapping (address => mapping (address => uint256)) private _allowances;

mapping (address => bool) private _isExcluded; // ob Nutzer vom r-space ausgenommen sind
address[] private _excluded; // Konten, die vom r-space ausgenommen sind
```dann definiert er die wesentlichen Konstanten des Vertrags. Es ist zu beobachten, dass `_rTotal` auf ein bestimmtes Vielfaches von `_tTotal` (d.h. die `totalSupply` des Tokens, die als Rückgabewert der `totalSupply`-Funktion verwendet wird) gesetzt ist:

```solidity
uint256 private constant MAX = ~uint256(0);
uint256 private constant _tTotal = 10 * 10**6 * 10**9;
uint256 private _rTotal = (MAX - (MAX % _tTotal));
```aus der Perspektive der Funktionalität und Benutzerinteraktion fallen die Funktionen dieses Vertrags in die folgenden drei Kategorien: ***Guthabeneinsicht und Token-Übertragung, zusammen mit einer charakteristischen Reflexionsfunktion***. Die ersten beiden sind mit dem ERC-20-Standard kompatibel, die interne Logik unterscheidet sich jedoch von anderen ERC-20-Token. Jede dieser Funktionen wird unten näher erläutert.

#### 0x1.2.1 Funktionen zur Guthabeneinsicht

Die Guthabenberechnung unterscheidet sich für ausgeschlossene und nicht ausgeschlossene Nutzer:
```solidity
function balanceOf(address account) public view override returns (uint256) {
    if (_isExcluded[account]) return _tOwned[account];
    return tokenFromReflection(_rOwned[account]);
}

function tokenFromReflection(uint256 rAmount) public view returns(uint256) {
    require(rAmount <= _rTotal, "Amount must be less than total reflections");
    uint256 currentRate =  _getRate();
    return rAmount.div(currentRate);
}
```dies kann durch die folgende Formel ausgedrückt werden:

 ![](https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/1_Photoroom_7990dc16c1.png) 

Die *Rate* in der obigen Formel wird durch Aufruf der Funktion `_getRate` berechnet, die tatsächlich aus dem Rückgabewert der Funktion `_getCurrentSupply` innerhalb des Vertrags berechnet wird.

```solidity
function _getRate() private view returns(uint256) {
    (uint256 rSupply, uint256 tSupply) = _getCurrentSupply();
    return rSupply.div(tSupply);
}

function _getCurrentSupply() private view returns(uint256, uint256) {
    uint256 rSupply = _rTotal;
    uint256 tSupply = _tTotal;      
    for (uint256 i = 0; i < _excluded.length; i++) {
        if (_rOwned[_excluded[i]] > rSupply || _tOwned[_excluded[i]] > tSupply) return (_rTotal, _tTotal);
        rSupply = rSupply.sub(_rOwned[_excluded[i]]);
        tSupply = tSupply.sub(_tOwned[_excluded[i]]);
    }
    if (rSupply < _rTotal.div(_tTotal)) return (_rTotal, _tTotal);
    return (rSupply, tSupply);
}
```es ist nicht schwierig, die entsprechende Formel aus dem obigen Code-Snippet abzuleiten:

 ![](https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/2_Photoroom_a6fcca8135.png) 

#### 0x1.2.2 Funktionen zur Token-Übertragung

Im Allgemeinen gibt es vier Szenarien für die Übertragung von Vermögenswerten, wie folgt:

```solidity
function _transfer(address sender, address recipient, uint256 amount) private {
    require(sender != address(0), "ERC20: transfer from the zero address");
    require(recipient != address(0), "ERC20: transfer to the zero address");
    require(amount > 0, "Transfer amount must be greater than zero");
    if (_isExcluded[sender] && !_isExcluded[recipient]) {
        _transferFromExcluded(sender, recipient, amount); // t-space -> r-space
    } else if (!_isExcluded[sender] && _isExcluded[recipient]) {
        _transferToExcluded(sender, recipient, amount); // r-space -> t-space
    } else if (!_isExcluded[sender] && !_isExcluded[recipient]) {
        _transferStandard(sender, recipient, amount); // r-space -> r-space
    } else if (_isExcluded[sender] && _isExcluded[recipient]) {
        _transferBothExcluded(sender, recipient, amount); // t-space -> t-space
    } else {
        _transferStandard(sender, recipient, amount); // r-space -> r-space
    }
}

Für ausgeschlossene Konten müssen sowohl _rOwned als auch _tOwned zum jeweiligen Raum hinzugefügt oder davon abgezogen werden. Für nicht ausgeschlossene Konten muss nur _rOwned berücksichtigt werden. Zum Beispiel zeigt der folgende Code-Ausschnitt die Implementierung der Übertragung von Vermögenswerten vom r-space in den t-space, wobei sender ein nicht ausgeschlossenes Konto und recipient ein ausgeschlossenes Konto ist.

function _transferToExcluded(address sender, address recipient, uint256 tAmount) private {
    (uint256 rAmount, uint256 rTransferAmount, uint256 rFee, uint256 tTransferAmount, uint256 tFee) = _getValues(tAmount);
    _rOwned[sender] = _rOwned[sender].sub(rAmount);
    _tOwned[recipient] = _tOwned[recipient].add(tTransferAmount);
    _rOwned[recipient] = _rOwned[recipient].add(rTransferAmount);           
    _reflectFee(rFee, tFee);
    emit Transfer(sender, recipient, tTransferAmount);
}
```- Die Funktion `_getValues` berechnet den entsprechenden Betrag, den Übertragungsbetrag und die Gebühr (d.h. *Betrag* = *Übertragungsbetrag* + *Gebühr*) für beide Räume.

    ```solidity
    function _getValues(uint256 tAmount) private view returns (uint256, uint256, uint256, uint256, uint256) {
        (uint256 tTransferAmount, uint256 tFee) = _getTValues(tAmount);
        uint256 currentRate =  _getRate();
        (uint256 rAmount, uint256 rTransferAmount, uint256 rFee) = _getRValues(tAmount, tFee, currentRate);
        return (rAmount, rTransferAmount, rFee, tTransferAmount, tFee);
    }
    ```

- Die Funktion `_reflectFee` reflektiert die Gebühr im r-space. Insbesondere wird `_rTotal` um die Gebühr im r-space (d.h. `rFee`) reduziert, was wiederum die *Rate* senkt. Gemäß der Formel zur Berechnung des *balanceOf(user)* werden auf diese Weise Gebühren an alle nicht ausgeschlossenen Token-Inhaber reflektiert.

    ```solidity
    function _reflectFee(uint256 rFee, uint256 tFee) private {
        _rTotal = _rTotal.sub(rFee);
        _tFeeTotal = _tFeeTotal.add(tFee);
    }
    ```

#### 0x1.2.3 Die `reflect`-Funktion

Zusätzlich zur passiven Auslösung des Reflexionstoken-Mechanismus während des Übertragungsprozesses können Nutzer die Funktion `reflect` aktiv aufrufen, um diesen Mechanismus zu initiieren. Insbesondere ***wenn jemand die von ihm gehaltenen Token konsumiert, um diese Funktion aufzurufen, sinkt die Rate, da `rSupply` abnimmt, wodurch andere Token-Inhaber profitieren***. Mit anderen Worten, sich selbst opfern, um anderen zu helfen. Auf diese Weise können die Projektbetreiber die Token-Inhaber durch die Nutzung dieser Funktion anregen.

```solidity
function reflect(uint256 tAmount) public {
    address sender = _msgSender();
    require(!_isExcluded[sender], "Excluded addresses cannot call this function");
    (uint256 rAmount,,,,,,) = _getValues(tAmount);
    _rOwned[sender] = _rOwned[sender].sub(rAmount);
    _rTotal = _rTotal.sub(rAmount);
    _tFeeTotal = _tFeeTotal.add(tAmount);
}
```die oben angegebenen Codes bilden den Kern des Mechanismus. Unterschiedliche Token können spezifische zusätzliche Funktionen enthalten, um ihre Implementierung anzupassen. Einige verwenden beispielsweise Transaktionsgebühren, um eine "Swap and Liquify"-Funktion zu betreiben und einen Ansturm zu verhindern, wenn Wale beschließen, ihre Token zu verkaufen.

## 0x2 Post-Mortem von Rekt Reflexionstoken

Wie bereits erwähnt, konzentrieren wir uns hauptsächlich auf ***Angriffe, die den Reflexionstoken-Mechanismus ausnutzen***. Daher werden Vorfälle, die nichts mit diesem Mechanismus zu tun haben, wie der [SafeMoon V2-Angriff](https://twitter.com/BlockSecTeam/status/1640894449122422784) (ein übliches ERC20-Problem mit öffentlichem Verbrennen) und der kürzliche [ZongZi-Angriff](https://twitter.com/0xNickLFranklin/status/1772195949638775262) (bezogen auf eine altmodische Preismanipulation, die den Spotpreis ausnutzt), nicht behandelt.

Wir haben diese Angriffe eingehend analysiert, um ihre Grundursachen zu entschlüsseln. Eine Liste aller dieser Vorfälle finden Sie [hier](https://uwin.notion.site/Rekt-Reflection-Tokens-fe524d676a294bbd901be80475fe5284). Wir haben festgestellt, dass die meisten von ihnen ***normale*** Sicherheitsvorfälle sind, die entweder auf Code-Schwachstellen oder auf unsachgemäße administrative Operationen zurückzuführen sind. Einige wenige sind jedoch recht verdächtig (z. B. das Vorhandensein einer Hintertür), die wir als ***abnormale*** Sicherheitsvorfälle bezeichnen. In den folgenden Unterabschnitten werden wir zunächst die normalen Sicherheitsvorfälle vorstellen und dann die abnormalen im Detail behandeln.

### 0x2.1 Normale Sicherheitsvorfälle

Unsere Untersuchung legt nahe, dass diese Vorfälle auf zwei Arten von Problemen zurückzuführen sind, d.h. ***Probleme auf Code-Ebene*** und ***Probleme auf Betriebsebene***, entweder einzeln oder in Kombination.

1. ***Probleme auf Code-Ebene***. Dies ergibt sich aus der **schlechten Implementierung** des Vertrags, wahrscheinlich weil die Entwickler den Mechanismus des Reflexionstokens nicht vollständig verstanden haben, was zu **einer Inkonsistenz zwischen dem tatsächlichen Angebot an Token und dem aufgezeichneten Wert von `totalSupply`** führt, die zur Manipulation der Rate verwendet werden kann:
    
    - 1.1 Nullkosten-Verbrennung

    - 1.2 Zusätzliche Abzüge von `rSupply` während Token-Übertragungen

    - 1.3 Verwechslung zwischen r-space- und t-space-Werten (mit Präzisionsverlust zur Gewinnerzielung)

2. ***Probleme auf Betriebsebene***. Dies ergibt sich aus **unsachgemäßer Bedienung durch Administratoren**. Insbesondere bezieht sich dies bei diesen Vorfällen auf die unsachgemäße Konfiguration der AMM-Paaradressen, die nicht ordnungsgemäß ausgenommen wurden.

Es ist erwähnenswert, dass ***ALLE*** aufgeführten Probleme auf Code-Ebene zu Inkonsistenzen zwischen dem tatsächlichen Angebot und `totalSupply` führen könnten, was die Verträge anfällig macht. ***Dies bedeutet jedoch nicht unbedingt, dass diese Schwachstellen ausnutzbar sind oder, genauer gesagt, profitabel genug, um sie auszunutzen***, da es für den Angreifer Kosten geben könnte, die Rate zu manipulieren. Der Einfachheit halber werden wir im Folgenden den Begriff "ausnutzbar" für "profitabel genug, um ausnutzbar zu sein" verwenden. Folglich ist in einigen Szenarien ein Problem auf Betriebsebene erforderlich, um diese Schwachstellen ausnutzbar zu machen.
Insbesondere kann Problem 1.1 direkt ausgenutzt werden, während Probleme 1.2 und 1.3 eine Kombination mit Problem 2 erfordern, um ausnutzbar zu werden. Daher können die diskutierten Vorfälle basierend auf diesen Beobachtungen in zwei Typen, **Typ-I** und **Typ-II**, unterteilt werden. Nachfolgend finden Sie eine Tabelle mit den relevanten Daten:

| Typ | Vorfall(e) | Grundursache(n) | # (%) |
|:----:|:------------------:|:------------------:|:----:|
| I | CATOSHI | Nur Problem auf Code-Ebene (1.1) | 1 (0.79%) |
| II (a) | BEVO, FETA, ADU | Kombination aus beidem (1.2 & 2) | 3 (2.38%) |
| II (b) | SHEEP und 120+ andere | Kombination aus beidem (1.3 & 2) | 122 (96.83%) |

Die Tabelle zeigt, dass Typ-II-Vorfälle einen erheblichen Anteil ausmachen. Insbesondere gibt es 2 Varianten innerhalb von Typ-II: **Typ-II-a** (d.h. Problem 1.2 mit Problem 2) und **Typ-II-b** (d.h. Problem 1.3 mit Problem 2). Darüber hinaus legen die Exploits bei Vorfällen vom Typ SHEEP der Kategorie Typ-II-b nahe, dass Angreifer (z. B. [dieser hier](https://bscscan.com/address/0xe935847fb8216635264111b5b5de0fd0cbc6f77d)) möglicherweise automatisierte Methoden verwenden, um ähnlich anfällige Verträge zu identifizieren. Spezifische Details werden in den folgenden Unterabschnitten behandelt.

#### 0x2.1.1 Typ-I: Nur Problem auf Code-Ebene (Problem 1.1)

Nur ein Vorfall gehört zu Typ-I, d.h. der [CATOSHI-Vorfall](https://app.blocksec.com/explorer/tx/eth/0x2cfbf76f1f9e3bc458c6578114cf6f184fa1bc2eb19a09c95c04a352f9f610fa), eine Nullkosten-Verbrennung, die die Gesamtzahl betrifft.

Werfen wir zunächst einen Blick auf die Funktion `burnOf` im [CATOSHI-Vertrag](https://etherscan.io/address/0xa10989335f3ba92bd43e60fbe8d42fe739412ac4):

```solidity
function burnOf(uint256 tAmount) public {
    uint256 currentRate = _getRate();
    uint256 rAmount = tAmount.mul(currentRate);
    _tTotal = _tTotal.sub(tAmount);
    _rTotal = _rTotal.sub(rAmount);
    emit Transfer(_msgSender(), address(0), tAmount);
}
```offensichtlich wird der von dieser Funktion verbrannte Betrag nicht vom Aufrufer (d.h. msg.sender) abgezogen. ***`_rOwned[msg.sender]` sollte jedoch um `rAmount` reduziert werden, und wenn das Konto ausgeschlossen ist, sollte `_tOwned[msg.sender]` ebenfalls um `tAmount` reduziert werden.***

Aufgrund dieses Versehen können Angreifer zunächst eine große Menge an Token kostenlos verbrennen und dann die `reflect`-Funktion des Vertrags aufrufen. Da sowohl `_tTotal` als auch `_rTotal` proportional stark reduziert wurden:

 ![](https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/3_Photoroom_75b234307b.png) 

Die *Rate* kann durch Aufruf der Funktion `reflect` leicht nach unten manipuliert werden, wodurch sich *balanceOf(attacker)* erheblich erhöht. Dies ermöglicht es Angreifern, von dem aufgeblähten Guthaben zu profitieren.

 ![](https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/4_Photoroom_f7c6dfa594.png) 

<center style="margin-bottom: 16px">
	    <img width="90%" height="auto"
	    src="https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/CATOSHI_944fcdca96.png" >
</center>


Warum? Beachten Sie, dass das neue Guthaben des Angreifers wie folgt berechnet wird:

 ![](https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/5_Photoroom_949997a762.png) 
 
Das Verhältnis zwischen *balanceOf(attacker)* und *balanceOf(attacker)'* ist:

 ![](https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/6_Photoroom_61fd493655.png) 

Da

 ![](https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/7_f49c61ada5.png) 

Daher

 ![](https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/8_3f82f7cdcb.png) 

Das bedeutet, dass der Angreifer mehr Token erntet, die gegen wertvolle Token (in diesem Fall WETH) getauscht werden können, um Gewinne zu erzielen.

#### 0x2.1.2 Typ-II-a: Kombination aus Problem 1.2 und Problem 2

Vorfälle vom Typ Typ-II-a beinhalten die Kombination von zwei Problemen:

- Problem 1.2: Zusätzliche Abzüge von `rSupply` während Token-Übertragungen.
- Problem 2: AMM-Paar ist nicht ausgenommen.

Bei Typ-II-a gibt es drei Angriffs-Vorfälle, die weiter in zwei Unterkategorien unterteilt werden können, entsprechend den Schwachstellenformen in Problem 1.2, wie folgt:

**1. Zusätzliche Reflexion in der _reflectFee Funktion**

Zwei Vorfälle gehören zu dieser Unterkategorie, d.h. der [BEVO-Vorfall](https://app.blocksec.com/explorer/tx/bsc/0xb97502d3976322714c828a890857e776f25c79f187a32e2d548dda1c315d2a7d) und der [FETA-Vorfall](https://app.blocksec.com/explorer/tx/bsc/0xa07bf86c1d8df2ad889888bd0cf54babfb25fad046ec0ae6e27272746ecd66e8). Im Folgenden verwenden wir den [BEVO-Vertrag](https://bscscan.com/address/0xc6cb12df4520b7bf83f64c79c585b8462e18b6aa) zur Veranschaulichung.

Wie in "Funktionen zur Token-Übertragung" (Abschnitt 0x1.2.2) erläutert, löst jede Token-Übertragung die Reflexion eines Teils der Transaktionsgebühr aus. In BEVO werden die Gebühren neben der ursprünglichen noch in zwei zusätzliche Teile unterteilt: ***Verbrennung*** und ***Spende***.

```solidity
function _reflectFee(uint256 rFee, uint256 rBurn, uint256 rCharity, uint256 tFee, uint256 tBurn, uint256 tCharity) private {
    _rTotal = _rTotal.sub(rFee).sub(rBurn).sub(rCharity); // rCharity wird von _rTotal abgezogen
    _tFeeTotal = _tFeeTotal.add(tFee);
    _tBurnTotal = _tBurnTotal.add(tBurn);
    _tCharityTotal = _tCharityTotal.add(tCharity);
    _tTotal = _tTotal.sub(tBurn);
}
```beachten Sie, dass ***das Spendenkonto ausgeschlossen ist, was bedeutet, dass der an dieses Konto gesendete Betrag verbrannt wird***, wie in der Funktion `_sendToCharity` gezeigt.
```solidity
function _sendToCharity(uint256 tCharity, address sender) private {
    uint256 currentRate = _getRate();
    uint256 rCharity = tCharity.mul(currentRate);
    address currentCharity = _charity[0];
    _rOwned[currentCharity] = _rOwned[currentCharity].add(rCharity);
    _tOwned[currentCharity] = _tOwned[currentCharity].add(tCharity); // da das Spendenkonto ausgeschlossen ist, wird der Spendenanteil verbrannt
    emit Transfer(sender, currentCharity, tCharity);
}
```aus dem obigen Code-Schnipsel können wir sehen, dass es zwei Stellen gibt, an denen der Spendenanteil reflektiert und verbrannt wird, was zu einer Inkonsistenz des tatsächlichen Token-Angebots mit der `totalSupply` während der Übertragungen führt. Mit zunehmender Anzahl von übertragenen Token ist der Wert von `rSupply` aufgrund des zusätzlichen Rückgangs geringer als das Angebot an Token im Pool.

> Die rein theoretische Beschreibung mag etwas abstrakt sein, daher verwenden wir ein Beispiel zur Veranschaulichung des Prozesses. Angenommen, Alice möchte 10 Token an Bob übertragen, und 3 Token werden wie folgt abgezogen: 1 für die Gebühr, 1 für die Verbrennung und 1 für die Spende. Da der Spendenanteil sowohl reflektiert als auch verbrannt wird, beträgt die tatsächliche Aufschlüsselung 2 Token, die reflektiert werden (1 Gebühr + 1 Spende), und 2 Token, die verbrannt werden (1 Verbrennung + 1 Spende). Zusammen mit den verbleibenden 7 zu übertragenden Token an Bob sind insgesamt 11 Token an diesem Prozess beteiligt, was fehlerhaft ist.

Aber warum kann diese Inkonsistenz ausgenutzt werden, um Gewinne zu erzielen? Im Folgenden werden wir unseren mathematischen Zauberstab schwingen, um die Folgen abzuleiten.

Angenommen, wir haben zuvor einige Token aus dem Pool (d.h. PancakeSwap-Paar) erworben, bezeichnet als *rAmount* im r-space und *tAmount* im t-space. Da ***der Pool nicht ausgenommen wurde***, bezeichnen wir `_rOwned[pair]` als *rReserve*, mit dem entsprechenden Wert im t-space ebenfalls als *tReserve* bezeichnet. Dann haben wir:

 ![](https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/9_Photoroom_0aa75f1ea6.png) 

Aufgrund des zusätzlichen Rückgangs ist `rSupply` jetzt geringer als das Angebot an Token im Pool:

 ![](https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/10_Photoroom_bb05e20fcb.png) 

Erinnern wir uns an den Abschnitt "Funktionen zur Guthabeneinsicht" (0x1.2.1), die aktuelle *Rate* kann mit der folgenden Formel berechnet werden:

 ![](https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/11_removebg_preview_caa44c3932.jpg) 

Zu diesem Zeitpunkt, wenn wir die von uns gehaltenen Token über die Funktion `reflect` (die in diesem Vertrag in `deliver` umbenannt wurde) reflektieren, wird die *Rate* zu *rate'*:

 ![](https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/12_Photoroom_74f7648d75.png) 

Da

 ![](https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/13_Photoroom_0731d6b174.png) 

Dann haben wir

 ![](https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/14_removebg_preview_c48a8d7c3f.jpg) 

Durch Kombination der Formeln 1, 3 und 6 können wir die folgende Ungleichung ableiten:

 ![](https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/15_Photoroom_419c9ec12f.png) 

Dies bedeutet, dass die Anzahl der Token, die wir direkt aus dem Pool (über die Funktion `skim`) ernten können, **noch größer ist als** das, was wir geliefert haben, was profitabel ist, da die Kosten für den Aufruf der Funktion `reflect` gedeckt werden können. Danach kann der Angreifer die geernteten Token gegen wertvolle Token (in diesem Fall WBNB) tauschen, um einen Gewinn zu erzielen.

<center style="margin-bottom: 16px">
	    <img width="90%" height="auto"
src="https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/BEVO_trace_cdb8e14957.png" >
</center>

Beachten Sie, dass der BEVO-Vertrag auch anfällig für Problem 1.3 ist, das im Angriff nicht ausgenutzt wurde.

**2. Falsche rTransferAmount-Berechnung in der _getRValues Funktion**

Nur ein Vorfall gehört zu dieser Form, d.h. der [ADU-Vorfall](https://app.blocksec.com/explorer/tx/bsc/0xc6f6b70e9e35770b699da9b60244d461d02db66859df42319c3207d76931423c). Betrachten wir zunächst den folgenden Code-Schnipsel.

```solidity
function _transferStandard(address sender, address recipient, uint256 tAmount) private {
    (uint256 rAmount, uint256 rTransferAmount, uint256 rFee, uint256 tTransferAmount, uint256 tFee, uint256 tTeam) = _getValues(tAmount);
    _rOwned[sender] = _rOwned[sender].sub(rAmount);
    _rOwned[recipient] = _rOwned[recipient].add(rTransferAmount);
    _takeTeam(tTeam);
    _reflectFee(rFee, tFee);
    emit Transfer(sender, recipient, tTransferAmount);
}

function _getValues(uint256 tAmount) private view returns (uint256, uint256, uint256, uint256, uint256, uint256) {
    (uint256 tTransferAmount, uint256 tFee, uint256 tTeam) = _getTValues(tAmount, _taxFee, _teamFee);
    uint256 currentRate =  _getRate();
    (uint256 rAmount, uint256 rTransferAmount, uint256 rFee) = _getRValues(tAmount, tFee, currentRate);
    return (rAmount, rTransferAmount, rFee, tTransferAmount, tFee, tTeam);
}

function _getTValues(uint256 tAmount, uint256 taxFee, uint256 teamFee) private pure returns (uint256, uint256, uint256) {
    uint256 tFee = tAmount.mul(taxFee).div(100);
    uint256 tTeam = tAmount.mul(teamFee).div(100);
    uint256 tTransferAmount = tAmount.sub(tFee).sub(tTeam); // tTeam wird von tAmount abgezogen
    return (tTransferAmount, tFee, tTeam);
}

function _getRValues(uint256 tAmount, uint256 tFee, uint256 currentRate) private pure returns (uint256, uint256, uint256) {
    uint256 rAmount = tAmount.mul(currentRate);
    uint256 rFee = tFee.mul(currentRate);
    uint256 rTransferAmount = rAmount.sub(rFee); // Allerdings wird kein rTeam von rAmount abgezogen
    return (rAmount, rTransferAmount, rFee);
}
```wir sehen, dass sowohl die Steuergebühr als auch die Teamgebühr bei Übertragungen abgezogen werden sollten. In der Funktion `_getTvalues` wird jedoch `tTransferAmount` um `tFee` und `tTeam` subtrahiert, während in der Funktion `_getRValues` nur `rFee` subtrahiert wird. Diese Diskrepanz führt zu dem zuvor erwähnten Inkonsistenzproblem, das sich mit zunehmender Anzahl von Token-Übertragungen verschlimmert.

Da das Paar im Token ebenfalls nicht ausgenommen ist, ist dieser Token ausnutzbar. Insbesondere könnte ein Angreifer ähnliche BEVO-Exploits verwenden, um über die `skim`-Funktion des Paares mehr ADU-Token zu ernten, nachdem die `deliver`-Funktion aufgerufen wurde.

Angesichts des damaligen On-Chain-Status war es jedoch für den Angreifer unmöglich, die geernteten ADU-Token gegen WBNB zu tauschen, um Gewinne zu erzielen (aufgrund der `require`-Anweisung in der Funktion `tokenFromReflection`). Daher müsste der Angreifer eine komplexere Ausnutzungsstrategie anwenden, um Gewinne zu erzielen, die hier nicht näher erläutert wird.

```solidity
function tokenFromReflection(uint256 rAmount) public view returns(uint256) {
    require(rAmount <= _rTotal, "Amount must be less than total reflections");
    uint256 currentRate =  _getRate();
    return rAmount.div(currentRate);
}
```#### 0x2.1.3 Typ-II-b: Kombination aus Problem 1.3 und Problem 2

Vorfälle vom Typ Typ-II-b beinhalten die Kombination von zwei Problemen:

- Problem 1.3: Verwechslung zwischen r-space- und t-space-Werten (wobei zu beachten ist, dass auch ein Präzisionsverlust vorhanden sein muss, um Gewinne zu erzielen).
- Problem 2: AMM-Paar ist nicht ausgenommen.

Problem 1.3 ergibt sich aus der fehlerhaften Handhabung von Werten zwischen r-space und t-space während der Implementierung der internen Funktion `_burn`.

```solidity
function burn(uint256 _value) public {
    _burn(msg.sender, _value);
}

function _burn(address _who, uint256 _value) internal {
    require(_value <= _rOwned[_who]);
    _rOwned[_who] = _rOwned[_who].sub(_value); // _rOwned sollte um einen r-space-Wert reduziert werden
    _tTotal = _tTotal.sub(_value); // _tTotal sollte um einen t-space-Wert reduziert werden
    // Für die Semantik der burn-Funktion sollte auch _rTotal von einem r-space-Wert abgezogen werden.
    emit Transfer(_who, address(0), _value);
}
```unter Berücksichtigung der wesentlichen Konstanten des Vertrags ist der r-space-Wert typischerweise ein großes Vielfaches des t-space-Werts. Daher wird durch den Aufruf der `burn`-Funktion mit einem `_value`, der in der Größenordnung von `tSupply` liegt, die *Rate* erheblich aufgebläht.

Im Gegensatz zu den Fällen vom Typ I kann der Aufrufer jedoch keine Token verbrennen, während sein eigenes Guthaben unverändert bleibt. Das heißt, es ist schwierig, wenn nicht gar unmöglich, für den Angreifer, mehr Token zu ernten. Wie konnten also die Fälle vom Typ II-b ausnutzbar sein?

Am Beispiel des [SHEEP-Token-Vorfalls](https://twitter.com/BlockSecTeam/status/1623999717482045440) können die *Werte* der vom Angreifer gehaltenen SHEEP-Token wie folgt bezeichnet werden:


 ![](https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/16_removebg_preview_a5e6593501.jpg) 

Wo der Preis von `SHEEP` durch den Spotpreis im PancakeSwap-Paar ausgedrückt werden kann, berechnet als:

 ![](https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/17_removebg_preview_db7b453e32.jpg) 

Dann kann der *Wert* weiter wie folgt ausgedrückt werden:

 ![](https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/18_removebg_preview_ba5ef0e654.jpg) 

Der Angreifer führt dann wiederholt die `burn`-Funktion aus und synchronisiert schließlich das Paar. Da weder der Angreifer noch das Paar ausgenommen sind, sinken ihre Guthaben aufgrund der oben erwähnten *Rate*-Inflation. Somit passt sich das Verhältnis an:

 ![](https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/19_removebg_preview_3af14ddc04.jpg) 

Basierend auf den vorherigen Definitionen können wir diese Verhältnisse weiter ausdrücken als:

 ![](https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/20_removebg_preview_f103b7ee5e.jpg) 

Wobei *X* die Summe der verbrannten `_value` darstellt.

***Hier kommt die Magie***: Das letztere Verhältnis ist eindeutig kleiner als das erstere, wenn wir 8 und 9 weiter vereinfachen, was uns wundert, da der Gewinn in diesem Fall ein negativer Wert wäre:

 ![](https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/21_removebg_preview_fc3b0c0430.jpg) 

Tatsächlich nutzte der Angreifer ein **Präzisionsverlust**-Problem im Reflexionstoken aus. Für nicht ausgenommene Nutzer wird, gemäß der von uns bereitgestellten Formel, die Guthabenberechnung in der Funktion `tokenFromReflection` tatsächlich abgerundet. Daher kann der Rückgabewert der `balanceOf`-Abfrage kleiner sein als sein theoretischer Wert. Das heißt, das *Verhältnis'* kann größer sein als das *Verhältnis*, wenn wir dieses Problem berücksichtigen.

```solidity
function tokenFromReflection(uint256 rAmount) public view returns(uint256) {
    require(rAmount <= _rTotal, "Amount must be less than total reflections");
    uint256 currentRate =  _getRate();
    return rAmount.div(currentRate);
}
```durch das Debuggen der [Angriffstransaktion](https://app.blocksec.com/explorer/tx/bsc/0x61293c6dd5211a98f1a26c9f6821146e12fb5e20c850ad3ed2528195c8d4c98e), können wir die theoretischen Guthaben des Angreifers und des Paares vor und nach diesen Manipulationen berechnen. Die Ergebnisse unserer Berechnungen sind in der folgenden Tabelle aufgeführt:

<center style="margin-bottom: 16px">
	    <img width="90%" height="auto"
src="https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/SHEEP_table_161818e8d1.png" >
</center>

> Δ in der Tabelle ist ein extrem kleiner Wert, weit unter 1.

Durch die Analyse des [Trace](https://app.blocksec.com/explorer/tx/bsc/0x61293c6dd5211a98f1a26c9f6821146e12fb5e20c850ad3ed2528195c8d4c98e?line=1984&debugLine=1984) innerhalb der Sync-Funktion des Paares können wir berechnen, dass die theoretischen Guthaben des Angreifers und des Paares tatsächlich 27,523 bzw. 2,972 betragen, was zu einem Verhältnis von 9,26 führt. Aufgrund des Präzisionsverlusts werden die Guthaben jedoch auf 27 bzw. 2 abgerundet, was das Verhältnis auf 13,50 aufbläht. Folglich wird der *Profit* zu einem positiven Wert.

<center style="margin-bottom: 16px">
	    <img width="90%" height="auto"
src="https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/SHEEP_trace_93ea56f079.png" >
</center>

Schließlich kann der Angreifer durch einen umgekehrten Swap Gewinn erzielen.

### 0x2.2 Abnormale Sicherheitsvorfälle

In diesem Unterabschnitt teilen wir unsere Erkenntnisse aus der Untersuchung der FDP- und DBALL-Token mit. Unsere Analyse deutet darauf hin, dass die Manager beider FDP- und DBALL-Token problematische privilegierte Funktionen aufgerufen haben, die effektiv als **Hintertüren** fungierten und die Projekte gefährdeten und letztendlich zu Angriffen führten. Insbesondere haben wir im DBALL-Projekt eine Reihe von verdächtigen Transaktionen des Token-Besitzers identifiziert, die klare Beweise dafür liefern, dass es sich um einen **Rug Pull** handelt.

Die Ausnutzung dieser beiden Token ähnelt stark der in den "Typ-II-a: Kombination aus Problem 1.2 und Problem 2" im Abschnitt 0x2.1.2 beschriebenen. Bei der Analyse der Gründe, warum das tatsächliche Token-Angebot von der `totalSupply` abweichen kann, treten jedoch einige verdächtige Aktivitäten zutage.

#### 0x2.2.1 Der FDP-Vorfall

Die Diskrepanz zwischen dem tatsächlichen Token-Angebot und der `totalSupply` im FDP-Fall beruht auf dem Aufruf der Funktion `transferOwnership`, einer privilegierten Funktion, die nur vom Vertragseigentümer aufgerufen werden kann. Wie der Name schon sagt, soll diese Funktion das Eigentum am Vertrag ändern. In [dem FDP-Vertrag](https://bscscan.com/address/0x1954b6bd198c29c3ecf2d6f6bc70a4d41ea1cc07#code) hat diese Funktion jedoch nichts mit der Eigentümerübertragung zu tun. Stattdessen erhöht sie `_rOwned[newOwner]`, ohne die `totalSupply` zu ändern. Dies verstößt eindeutig gegen die Designprinzipien des normalen Token-Minting-Prozesses.

```solidity
function transferOwnership(address newOwner) public virtual onlyOwner {
    (, uint256 rTransferAmount,, uint256 tTransferAmount,,) = _getValues(_tTotal);
    _rOwned[newOwner] = _rOwned[newOwner].add(rTransferAmount);       
    emit Transfer(address(0), newOwner, tTransferAmount);
}
```transaktionen die diese Funktion aufgerufen haben, sind in der folgenden Tabelle zusammengefasst:

| Zeitstempel | Transaktionshash | Aufrufer | Der `newOwner` |
|:---------:|:----------------:|:------:|:--------------:|
2021-06-05 17:23:57 | [0x46fa1f97...4606d9bc](https://bscscan.com/tx/0x46fa1f97a6f36f64d2bb0b267e889691ee29a66f708e40b0c1d55b7f4606d9bc) | [0xef309c...262586](https://bscscan.com/address/0xef309cbab1667b11962b5243931173a46a262586) | [0x9e96af...24481a](https://bscscan.com/address/0x9e96af507433abceb293658b82443aeebb24481a) |
2021-06-05 17:24:06 | [0x686e0d82...d6ebfb62](https://bscscan.com/tx/0x686e0d8211f3cdf8c9455928448acf3ff54869eb36aaf8fb21b83fccd6ebfb62) | [0xef309c...262586](https://bscscan.com/address/0xef309cbab1667b11962b5243931173a46a262586) | [0xb0c426...a72063](https://bscscan.com/address/0xb0c42673db6a9c30cfa9c0b2ed4d32c27ea72063) |
2021-06-05 17:26:12	| [0x44285339...7a526320](https://bscscan.com/tx/0x4428533974ce7817dcc0fafb11a8c0d3a12f34d7947d60d18ae97e077a526320) | [0xef309c...262586](https://bscscan.com/address/0xef309cbab1667b11962b5243931173a46a262586) | [0xef309c...262586](https://bscscan.com/address/0xef309cbab1667b11962b5243931173a46a262586) |
2021-06-05 19:39:00	| [0xaff7a688...dfe3f344](https://bscscan.com/tx/0xaff7a688aac1dc295680db820fa4459f88b5d9e7fb266078cf1102f5dfe3f344) | [0xef309c...262586](https://bscscan.com/address/0xef309cbab1667b11962b5243931173a46a262586) | [0x9e96af...24481a](https://bscscan.com/address/0x9e96af507433abceb293658b82443aeebb24481a) |
2022-06-05 18:08:10	| [0x2c413604...f7718f25](https://bscscan.com/tx/0x2c41360484c4cb1060563172b059d113918940be87c9aa759b52b2c4f7718f25) | [0xef309c...262586](https://bscscan.com/address/0xef309cbab1667b11962b5243931173a46a262586) | [0xef309c...262586](https://bscscan.com/address/0xef309cbab1667b11962b5243931173a46a262586) |
2022-06-05 18:49:16	| [0x8f4309ca...97d4bcec](https://bscscan.com/tx/0x8f4309ca129b1e1dfd23365c198c24bcaf2f1e970b4e6e781d2241d097d4bcec) | [0xef309c...262586](https://bscscan.com/address/0xef309cbab1667b11962b5243931173a46a262586) | [0xef309c...262586](https://bscscan.com/address/0xef309cbab1667b11962b5243931173a46a262586) |
2022-06-05 23:33:44	| [0xaa029544...3ff7b629](https://bscscan.com/tx/0xaa02954449a85a9b8416df255af487b1668c1f83ed5e0d6f8f3b651b3ff7b629) | [0xef309c...262586](https://bscscan.com/address/0xef309cbab1667b11962b5243931173a46a262586) | [0xef309c...262586](https://bscscan.com/address/0xef309cbab1667b11962b5243931173a46a262586) |

#### 0x2.2.2 Der DBALL-Vorfall

Bei DBALL wird es knifflig. Durch die Analyse des Fondsflusses [des DBALL-Besitzers](https://bscscan.com/address/0xbD239C0C8e41A3a1E1b83d915F0B2FBfAe72DAAE) mit [MetaSleuth](https://metasleuth.io/) beobachteten wir ein Ungleichgewicht im Zu- und Abfluss von DBALL-Token von dieser Adresse, wobei die Mittelherkunft für [diese Transaktion](https://app.blocksec.com/explorer/tx/bsc/0x616d22fa6c564bce10b2e9c80687aa3ab4ba410db21eefe4340a46529d802779) nicht aufgezeichnet wurde.

<center style="margin-bottom: 16px">
	    <img width="90%" height="auto"
src="https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/DBALL_owner_fund_flow_58ac8c8a25.png" >
</center>

Durch Abfrage der historischen Zustände auf der Kette haben wir schließlich festgestellt, dass sich das DBALL-Guthaben des Besitzers vor und nach [dieser Transaktion](https://app.blocksec.com/explorer/tx/bsc/0x97e9d60411122e12207bf2fd7740ad6ad482b433216806f3c73f041024adaadb) geändert hat. Wir können beobachten, dass der Besitzer die privilegierte Funktion `manualDevBurn` aufgerufen hat, um 1 Token im t-space zu verbrennen. Die Implementierung dieser Funktion ist wie folgt:

```solidity
function manualDevBurn (uint256 tAmount) public onlyOwner() {  
    uint256 rAmount = tAmount.mul(_getRate());
    if (_isExcluded[_msgSender()]) {
        _tOwned[_msgSender()] = _tOwned[_msgSender()] - (tAmount);
    }
    _rOwned[_msgSender()] = _rOwned[_msgSender()] - (rAmount);
    
    _tOwned[address(0)] = _tOwned[address(0)] + (tAmount);
    _rOwned[address(0)] = _rOwned[address(0)] + (rAmount);
    
    emit Transfer(_msgSender(), address(0), tAmount);
}
```auf den ersten Blick scheint alles in Ordnung zu sein. Aufgrund der Angabe einer Compiler-Version, die niedriger als 0.8 ist, tritt jedoch bei der Subtraktion von `_rOwned[_msgSender()]` ein **arithmetischer Unterlauf** auf, der von 0 auf fast `type(uint256).max` wechselt. Diese subtile Manipulation ermöglicht es dem Besitzer, sein Guthaben zu ändern, führt aber auch zu Inkonsistenzen im Token-Angebot.


Ist das nur ein versehentlicher Fehler? Unsere Untersuchung deutet darauf hin, dass es sich eher um einen vorsätzlichen Rug Pull handelt. Die Gründe sind wie folgt zusammengefasst:

1. Der Besitzer hat **nur 1** Token in die Funktion `manualDevBurn` übergeben, doch innerhalb einer halben Stunde wurde über [diese Transaktion](https://app.blocksec.com/explorer/tx/bsc/0x616d22fa6c564bce10b2e9c80687aa3ab4ba410db21eefe4340a46529d802779) eine Menge DBALL übertragen, die dem Gesamtangebot entspricht, an eine [zugehörige Adresse](https://bscscan.com/address/0x3a1a76635a2a09926194fadc7576a84fd87a9cd5).

2. Diese zugehörige Adresse hat sofort im PancakeSwap-Paar getauscht und erhielt ungefähr 56 WBNB.

<center style="margin-bottom: 16px">
	    <img width="90%" height="auto"
src="https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/DBALL_owner_peer_2cff4249ce.png" >
</center>

3. Die Analyse der [Fondsflüsse](https://metasleuth.io/result/bsc/0x3a1A76635A2A09926194FaDC7576a84Fd87A9cd5?source=43d5202e-6272-44f0-8224-37903503cd90) dieser beiden Adressen zeigt, dass beide schließlich BNB über Tornado.Cash überwiesen haben.

## 0x3 Ein potenzielles Problem bei der Berechnung der Rate

Über die zuvor besprochenen Vorfälle hinaus haben wir auch festgestellt, dass theoretisch ein potenzielles Problem bei der Guthabenberechnung von nicht ausgenommenen Nutzern besteht, das weiter diskutiert werden sollte. Dieses Problem kann bei der Berechnung der *Rate* auftreten.

Werfen wir einen Blick auf die Funktion `_getCurrentSupply`. In dieser Funktion bestimmt die abschließende `if`-Anweisung, ob `rSupply` geringer ist als die anfängliche Rate (d.h. *_rTotal / _tTotal*).

```solidity
function _getRate() private view returns(uint256) {
    (uint256 rSupply, uint256 tSupply) = _getCurrentSupply();
    return rSupply.div(tSupply);
}

function _getCurrentSupply() private view returns(uint256, uint256) {
    uint256 rSupply = _rTotal;
    uint256 tSupply = _tTotal;      
    for (uint256 i = 0; i < _excluded.length; i++) {
        if (_rOwned[_excluded[i]] > rSupply || _tOwned[_excluded[i]] > tSupply) return (_rTotal, _tTotal);
        rSupply = rSupply.sub(_rOwned[_excluded[i]]);
        tSupply = tSupply.sub(_tOwned[_excluded[i]]);
    }
    if (rSupply < _rTotal.div(_tTotal)) return (_rTotal, _tTotal);
    return (rSupply, tSupply);
}
```w des Lebenszyklus von der Vertragsbereitstellung bis zur Projektveröffentlichung würden, wenn diese Aussage zutrifft, die Guthaben aller nicht ausgenommenen Nutzer Null sein. Sobald das Projekt jedoch gestartet und Transaktionen begonnen haben, ging die ursprüngliche Absicht der `if`-Anweisung verloren.

Da `rSupply` aufgrund des Reflexionstoken-Mechanismus abnimmt, nimmt die *Rate* entsprechend ab. Wenn nach einer bestimmten Transaktion `rSupply` unter die anfängliche *Rate* fällt, springt die aktuelle *Rate* an, was zu Guthabenverlusten für alle nicht ausgenommenen Nutzer führt. Außerdem ist es theoretisch möglich, dass

 ![](https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/22_removebg_preview_12f080fd20.jpg) 

Dies führt dazu, dass die *Rate* aufgrund von Präzisionsverlust Null wird und möglicherweise eine Division-durch-Null-Panik auslöst.

### 0x4 Minderung und Lösungen

Der Reflexionstoken-Mechanismus bietet eine Möglichkeit, die Marktstabilität zu verbessern, indem er Anleger dazu anregt, ihre Token zu halten und nicht zu handeln, um zusätzliche Belohnungen zu erhalten. Er führt jedoch auch neue Sicherheitsherausforderungen und potenzielle Risiken ein, wie z. B. Verwechslungen zwischen r-space- und t-space-Werten. Daher ist es für Blockchain-Entwickler und Anleger entscheidend, ein besseres Verständnis des Mechanismus und seiner potenziellen Risiken zu erlangen und nach Lösungen zu suchen.

BlockSec bietet Sicherheitsdienste und -produkte für die Phasen vor und nach der Markteinführung. Unsere Sicherheitsaudit-Dienste führen gründliche Überprüfungen durch, um die Code-Sicherheit und Transparenz zu gewährleisten. Unser Phalcon-Produkt bietet kontinuierliche Sicherheitsüberwachung und Angreifererkennungsfunktionen, die es Betreibern und Anlegern ermöglichen, Projekte zu überwachen und automatische Maßnahmen bei Erkennung von Sicherheitsrisiken zu ergreifen.

**Verwandte Lektüre**

- [Wie L2-Blockchains ihre Nutzer besser schützen können](https://blocksec.com/blog/how-L2-blockchains-can-do-better-to-protect-their-users)
- [Top 10 "Awesome" Sicherheitsvorfälle im Jahr 2023](https://blocksec.com/blog/top-ten-awesome-security-incidents-in-2023)
- [Konzeptionelle vollständige Analyse eines Aufstiegs von Bitcoin mit Inschriften](https://blocksec.com/blog/conceptual-full-analysis-a-rise-of-bitcoin-with-inscription)


-----------



## Über BlockSec

BlockSec ist ein Full-Stack-Anbieter von Web3-Sicherheitsdiensten. Das Unternehmen engagiert sich für die Verbesserung von Sicherheit und Benutzerfreundlichkeit für die aufkommende Web3-Welt, um deren massenhafte Akzeptanz zu fördern. Zu diesem Zweck bietet BlockSec [Sicherheitsprüfungsdienste für Smart Contracts und EVM-Ketten](https://blocksec.com/code-audit), die [Phalcon-Plattform](https://blocksec.com/phalcon) für die Sicherheitsentwicklung und die proaktive Abwehr von Bedrohungen, die [MetaSleuth](https://metasleuth.io/)-Plattform für die Verfolgung und Untersuchung von Fonds sowie die [MetaSuites](https://blocksec.com/metasuites)-Erweiterung für Web3-Entwickler, um effizient in der Krypto-Welt zu surfen.

Bis heute hat das Unternehmen über 300 Kunden wie die Uniswap Foundation, Compound, Forta und PancakeSwap betreut und in zwei Finanzierungsrunden von namhaften Investoren wie Matrix Partners, Vitalbridge Capital und Fenbushi Capital zehn Millionen US-Dollar erhalten.

*   Website: [https://blocksec.com/](https://blocksec.com/)
*   E-Mail: [email protected]

*   Twitter: [https://twitter.com/BlockSecTeam](https://twitter.com/BlockSecTeam)
*   MetaSleuth: [https://metasleuth.io/](https://metasleuth.io/)
*   MetaSuites: [https://blocksec.com/metasuites](https://blocksec.com/metasuites)
Sign up for the latest updates
Tracing $1.6B in TRON USDT: Inside the VerilyHK Ponzi Infrastructure
Case Studies

Tracing $1.6B in TRON USDT: Inside the VerilyHK Ponzi Infrastructure

An on-chain investigation into VerilyHK, a fraudulent platform that moved $1.6B in TRON USDT through a multi-layered fund-routing infrastructure of rotating wallets, paired payout channels, and exchange exit funnels, with traced connections to the FinCEN-sanctioned Huione Group.

Weekly Web3 Security Incident Roundup | Mar 30 – Apr 5, 2026
Security Insights

Weekly Web3 Security Incident Roundup | Mar 30 – Apr 5, 2026

This BlockSec weekly security report covers nine DeFi attack incidents detected between March 30 and April 5, 2026, across Solana, BNB Chain, Arbitrum, and Polygon, with total estimated losses of approximately $287M. The week was dominated by the $285.3M Drift Protocol exploit on Solana, where attackers combined multisig signer social engineering with Solana's durable nonce mechanism to bypass a zero-timelock 2-of-5 Security Council, alongside notable incidents including a $950K flash loan TWAP manipulation against the LML staking protocol, a $359K Silo Finance vault inflation via an external `wstUSR` market donation exploiting a depegged-asset oracle and `totalAssets()` accounting flaw, and an EIP-7702 delegated-code access control failure. The report provides detailed vulnerability analysis and attack transaction breakdowns for each incident, covering flawed business logic, access control, price manipulation, phishing, and misconfiguration attack types.

Drift Protocol Incident: Multisig Governance Compromise via Durable Nonce Exploitation
Security Insights

Drift Protocol Incident: Multisig Governance Compromise via Durable Nonce Exploitation

On April 1, 2026 (UTC), Drift Protocol on Solana suffered a $285.3M loss after an attacker exploited Solana's durable nonce mechanism to delay the execution of phished multisig approvals, ultimately transferring administrative control of the protocol's 2-of-5 Squads governance with zero timelock. With full admin privileges, the attacker created a malicious collateral market (CVT), inflated its oracle price, relaxed withdrawal protections, and drained USDC, JLP, SOL, cbBTC, and other assets through 31 rapid withdrawals in approximately 12 minutes. This incident highlights how durable nonce-based delayed execution can decouple signer intent from on-chain execution, bypassing the temporal assumptions that multisig security implicitly relies on.