Threats & Research

Flash Loan Attack

CyStack image

Hà Minh Châu

|June 27, 2022

Mở đầu

Flash Loan Attack là một hình thức tấn công DeFi đã xuất hiện từ lâu, gây ra rất nhiều thiệt hại cho các nền tảng DeFi. Tính từ đầu năm 2022 đến nay, đã có nhiều cuộc tấn công dựa trên hình thức này, điển hình như các cuộc tấn công nhắm đến OneRing Finance, DEUS Finance, Elephant Money, Beanstalk Farms, v.v. Trong bài viết này, chúng ta sẽ tìm hiểu xem, Flash Loan Attack là gì cũng như các cách để phòng tránh Flash Loan Attack đối với các ứng dụng Defi.

Flash Loan là gì?

Flash Loan lần đầu được giới thiệu bởi Marble Protocol vào năm 2018 với tên gọi Flash Lending. Hiện nay, các nền tảng cho phép Flash Loan được biết đến phổ biến trên thị trường có AAVE, DyDx, Uniswap. Có thể hiểu đơn giản, Flash Loan là một dịch vụ cho người dùng vay nóng cryptocurrency.

Đối với các dịch vụ vay nợ truyền thống, luôn tồn tại hai rủi ro với người cho vay. Một là người dùng sau khi vay không có khả năng hoàn trả. Hai là người cho vay thực hiện cho vay quá nhiều tài sản, dẫn đến thanh khoản thấp, không có khả năng thực hiện được các tác vụ khác.

Tuy nhiên, với Flash Loan, hoàn toàn có thể giải quyết hai vấn đề trên. Flash Loan về cơ bản hoạt động như sau: Người vay sẽ được vay một khoản tùy ý mà không cần thế chấp, nhưng đồng thời, người vay cần phải đảm bảo việc hoàn trả lại số tiền đã vay trong cùng một giao dịch. Nếu người vay không thể trả được khoản vay trong cùng giao dịch đó, toàn bộ giao dịch sẽ bị revert, coi như chưa có gì xảy ra cả. Quy trình của một Flash Loan được minh họa trong lược đồ dưới đây:

Tưởng chừng như vô lý, nhưng tất cả những điều kiện này đều có thể được đáp ứng thông qua các smart contract. Để thực hiện một giao dịch Flash Loan, người dùng phải triển khai một smart contract mà trong đó thực hiện gọi đến hàm thực hiện chức năng Flash Loan của nền tảng cho vay tương ứng. Ví dụ minh họa dưới đây là hàm flashLoan ở nền tảng AAVE:

function flashLoan(address _receiver, address _reserve, uint256 _amount, bytes memory _params)
        public
        nonReentrant
        onlyActiveReserve(_reserve)
        onlyAmountGreaterThanZero(_amount)
    {
        // kiểm tra tính thanh khoản của reserve
        // hạn chế sử dụng hàm getAvailableLiquidity() trong LendingPoolCore
        // để tiết kiệm chi phí gas
        uint256 availableLiquidityBefore = _reserve == EthAddressLib.ethAddress()
            ? address(core).balance
            : IERC20(_reserve).balanceOf(address(core));

        require(
            availableLiquidityBefore >= _amount,
            "There is not enough liquidity available to borrow"
        );

        (uint256 totalFeeBips, uint256 protocolFeeBips) = parametersProvider
            .getFlashLoanFeesInBips();
        // tính tổng chi phí
        uint256 amountFee = _amount.mul(totalFeeBips).div(10000);

        // chi phí protocol là một phần của tổng chi phí, chi trả cho protocol,
        // phần còn lại dành cho những người gửi tài sản
        uint256 protocolFee = amountFee.mul(protocolFeeBips).div(10000);
        require(
            amountFee > 0 && protocolFee > 0,
            "The requested amount is too small for a flashLoan."
        );

        // tạo một instance FlashLoanReceiver (người thụ hưởng FlashLoan)
        IFlashLoanReceiver receiver = IFlashLoanReceiver(_receiver);

        address payable userPayable = address(uint160(_receiver));

        // chuyển khoản vay đến người thụ hưởng
        core.transferToUser(_reserve, userPayable, _amount);

        // thực hiện các giao dịch của người thụ hưởng
        receiver.executeOperation(_reserve, _amount, amountFee, _params);

        // kiểm tra số dư thực của contract có bao gồm chi phí vay hoàn lại hay không
        uint256 availableLiquidityAfter = _reserve == EthAddressLib.ethAddress()
            ? address(core).balance
            : IERC20(_reserve).balanceOf(address(core));

        require(
            availableLiquidityAfter == availableLiquidityBefore.add(amountFee),
            "The actual balance of the protocol is inconsistent"
        );

        core.updateStateOnFlashLoan(
            _reserve,
            availableLiquidityBefore,
            amountFee.sub(protocolFee),
            protocolFee
        );

        // solium-disable-next-line
        emit FlashLoan(_receiver, _reserve, _amount, amountFee, protocolFee, block.timestamp);
    }

Flash Loan để làm gì?

Vay không cần thế chấp với chi phí rẻ cho phép người dùng có thể làm nhiều rất nhiều thứ với số tiền vay được. Dưới đây là các ứng dụng thường gặp nhất của Flash Loan:

1. Giao dịch chênh lệch giá

Người dùng có thể sử dụng các khoản vay để kiếm lợi nhuận bằng cách giao dịch một tài sản trên nhiều nền tảng giao dịch khác nhau. Các bước thực hiện có thể như sau:

  • Người dùng vay 300.000 USDT từ AAVE;
  • Mua 100 ETH trên SushiSwap với giá 3.000 USDT;
  • Bán 100 ETH trên UniSwap với giá 3.100 USDT và thu về 310.000 USDT;
  • Trả khoản vay 300.000 USDT kém phí Flash Loan và thu về lợi nhuận.

2. Thay thế tài sản thế chấp

Người dùng có thể sử dụng Flash Loan để thay thế tài sản thế chấp với một bên cho vay nào đó. Ví dụ, người dùng đang thế chấp ETH ở nền tảng MakerDao, và muốn thay thế bằng BAT:

  • Người dùng sẽ thực hiện vay Flash Loan DAI trên AAVE;
  • Thanh lý khoản vay ETH;
  • Swap ETH thành BAT;
  • Thực hiện thế chấp BAT để vay DAI;
  • Trả khoản vay DAI và phí Flash Loan.

Flash Loan Attack là gì?

Flash Loan Attack thực chất là cách người dùng kiếm lợi nhuận từ giao dịch chênh lệch giá. Tuy nhiên, chúng được làm ở quy mô lớn hơn và ngoài ra, các giao thức DeFi bị tấn công có các điểm yếu, cho phép kẻ xấu có thể thao túng được sự chênh lệch giá này.

Các vụ Flash Loan Attack gần đây

1. Vụ tấn công Elephant Money vào ngày 12/04/2022

Elephant Money là một nền tảng mở cung cấp giải pháp tài chính toàn diện và được vận hành dựa trên các tài sản blue-chip, một rewards token chính là ELEPHANT và một “stable coin” gọi là TRUNK. TRUNK được duy trì tính ổn định theo công thức 1 TRUNK = 0,75 BUSD + 0,25 ELEPHANT.

Kẻ tấn công đã lợi dụng sự chênh lệch giá trong pool thanh khoản WBNB/ELEPHANT để kiếm lợi nhuận. Mấu chốt nằm ở đồng TRUNK và tính năng của Elephant Money cho phép người dùng sử dụng BUSD để quy đổi lấy TRUNK, với giá trị tương ứng gần như là 1:1 ở thời điểm xảy ra cuộc tấn công.

Contract cho phép sử dụng BUSD để mint ra TRUNK có địa chỉ 0xd520a3b47e42a1063617a9b6273b206a07bdf834.

Khi người dùng thực hiện gửi BUSD để mint TRUNK, contract trên có thực hiện thêm nhiều tác vụ khác, trong đó có một tác vụ là sử dụng khoảng 25% lượng BUSD được gửi vào để quy đổi sang WBNB, sau đó tiếp tục quy đổi sang ELEPHANT, khiến cho trong pool thanh khoản WBNB/ELEPHANT, đồng ELEPHANT sẽ tăng giá.

Cách thức thực hiện của kẻ tấn công như sau:

  • Flash Loan lần lượt 130.162 WBNB/1.000 WBNB/91.035.000 BUSD từ tương ứng các cặp Pancake USDT_WBNB/Cake_WBNB/USDT_BUSD;
  • Swap 131.162 WBNB thành 34.175.266.097.851 ELEPHANT, khiến cho đồng ELEPHANT trong pool WBNB/ELEPHANT tăng giá;
  • Thực hiện gửi 91.035.000 BUSD đến contract 0xd520a3b47e42a1063617a9b6273b206a07bdf834 để nhận về 90.124.650 TRUNK: Trong bước này, contract trên thực hiện swap 22.531.162 BUSD thành 48.882 WBNB, sau đó swap 48.882 WBNB thành 3.050.142.559.411 ELEPHANT khiến cho đồng ELEPHANT trong pool WBNB/ELEPHANT tiếp tục tăng giá. Ngoài ra một số tác vụ khác cũng được thực hiện, nhưng không ảnh hưởng đến giá đồng ELEPHANT;
  • Qua hai bước trên, giá của đồng ELEPHANT tăng giá, kẻ tấn công swap ngược lại 30.819.780.215.560 ELEPHANT để thu về 163.782 WBNB. Đây là bước chính để kẻ tấn công thu về lợi nhuận, so với bước swap trước đó, kẻ tấn công đã thu về lợi nhuận ít nhất là 32.000 WBNB.

Chi tiết về cuộc tấn công có thể xem thêm tại bài viết Reserve Exploit: Live Updates của Bankteller.

Dòng giao dịch diễn ra trong vụ tấn công Elephant Money, từ PeckShield

2. Vụ tấn công Beanstalk Farms vào ngày 17/04/2022

Beanstalk là một giao thức tín dụng stable coin phi tập trung vận hành dựa trên đồng $BEAN, gồm có ba thành phần chính là một oracle truy xuất giá phi tập trung, một hệ thống quản trị phi tập trung và một cơ sở dữ liệu cung cấp hạn mức tín dụng phi tập trung.

Về cơ bản, kẻ tấn công đã lợi dụng những cơ chế dưới đây của nền tảng Beanstalk để phát động vụ tấn công:

  • Beanstalk có sử dụng giao thức BIP18, cho phép người dùng tạo một kịch bản các giao dịch có sẵn;
  • Những người dùng khác có quyền biểu quyết sẽ thực hiện vote cho kịch bản giao dịch trên;
  • Khi kịch bản giao dịch trên đủ số lượng vote, nó sẽ có thể được thực hiện;
  • Quyền biểu quyết của mỗi người dùng sẽ phụ thuộc vào số lượng các token BEAN3CRV-f, BEANLUSD-f, v.v. được nạp vào Beanstalk: Beanstalk Protocol.

Cách thức thực hiện của kẻ tấn công:

  • Tạo 1 contract BIP18 proposal bao gồm các giao dịch có lợi cho kẻ tấn công;
  • Thực hiện Flash Loan lần lượt 350.000.000 DAI, 500.000.000 USDC, 150.000.000 USDT, 32.100.950 BEAN và 11.643.065 LUSD;
  • Thực hiện các swap nhằm tăng thanh khoản cần thiết để nhận được BEAN3CRV-f và BEANLUSD-f, sau đó nạp vào Beanstalk: Beanstalk Protocol để tăng quyền biểu quyết của kẻ tấn công;
  • Thực hiện vote cho contract BIP18 trên để thực thi contract này.

Chi tiết về cuộc tấn công có thể xem thêm tại chuỗi tweet phân tích của các chuyên gia bảo mật tại PeckShield.

Dòng giao dịch diễn ra trong vụ tấn công Beanstalk Farms, từ PeckShield

Cách thức phòng tránh Flash Loan Attack

1. Sử dụng các oracle phi tập trung để xác định giá

Cách tối ưu nhất để giảm tấn công cho việc khai thác flashloan là các nền tảng DeFi sử dụng các phương pháp định giá phi tập trung như Chainlink và Band Protocol thay vì dựa vào một DEX đơn lẻ.

2. Các giao dịch quan trọng cần phải được thực hiện trong hai block giao dịch

Các giao dịch quan trọng, ví dụ như nạp/rút để tăng tính biểu quyết, cần phải thực hiện trong hai giao dịch khác nhau. Có thể thực hiện đơn giản bằng cách chỉ cho phép người dùng rút tiền sau một khoảng thời gian so với thời điểm nạp tiền.

3. Thực hiện Smart Contract Audit

Các smart contract trước khi được triển khau lên mainnet cần thông qua các bài đánh giá bảo mật từ các công ty uy tín như CyStack.

Tổng kết

Flash Loan Attack hiện này đang là “vua của mọi nghề“, gây thiệt hại vô cùng lớn cho các nền tảng DeFi. Nhà phát triển smart contract cần phải có các kiểm tra bảo mật đối với các kịch bản tấn công liên quan đến Flash Loan. Tiến hành audit ngay các smart contract tại https://cystack.net/services/smart-contract-audit.

Huy Nguyễn – Security Engineer tại CyStack

Related posts

Cuộc tấn công vào ONUS – Góc nhìn kỹ thuật từ lỗ hổng Log4Shell
Cuộc tấn công vào ONUS – Góc nhìn kỹ thuật từ lỗ hổng Log4Shell
April 5 2023|Threats & Research

Read the English version here Log4Shell hiện đang là một cơn ác mộng (có lẽ là tồi tệ nhất cho tới thời điểm hiện tại) đối với nhiều doanh nghiệp. Không may thay, ONUS, một trong số những khách hàng của chúng tôi, đã trở thành nạn nhân của lỗ hổng này. Với tư cách […]

The attack on ONUS – A real-life case of the Log4Shell vulnerability
The attack on ONUS – A real-life case of the Log4Shell vulnerability
April 5 2023|Threats & Research

Đọc bản tiếng Việt tại đây Log4Shell has recently been a nightmare (probably the worst one for now) to businesses. ONUS, a client of ours, was an unfortunate victim. As their security partner, CyStack informed ONUS of the risks right after Log4Shell came to light; when the attack actually happened, we supported them in finding […]

Static binary injection with high-level code
Static binary injection with high-level code
April 5 2023|Threats & Research

Giới thiệu Static binary injection là một kỹ thuật dùng để chèn những đoạn code từ ngoài vào trong một file thực thi để theo dõi hoặc thay đổi hành vi của chương trình trong quá trình chạy. Nếu là một kẻ tấn công, hắn có thể sử dụng kỹ thuật này để thực hiện […]