# MO: borrow/redeem logic flaw drains USDT liquidity

MO lending contract on Optimism had a business logic flaw allowing repeated borrow/redeem cycles to drain ~413k USDT from the liquidity pair.

- Payout: Real-world hack
- Severity: high
- Program: MO
- Analysis by: DeFiHackLabs
- Disclosed: 2024-03-14
- Write-up quality: 6/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2024-03/MO_exp.sol
- Library page: https://bugbountylibrary.com/r/dhl%3A20240314-mo
- Tags: domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:high technique:chained vuln:accounting-error vuln:business-logic

**Target:** MO lending contract on Optimism
**Root cause:** The borrow and redeem functions could be called repeatedly in a loop, likely due to a flaw in order accounting or redemption logic that allowed the attacker to extract more value than deposited.
**Steps:**
1. Deploy attack contract and obtain 62,147,724 MO tokens via `deal`.
2. Approve MO and USDT to `approve_proxy` (0x9D8355a8D721E5c79589ac0aB49BC6d3e0eF7C3F).
3. Loop up to 80 times: call `LOAN.borrow(mo_balance, 0)` then `LOAN.redeem(i)`.
4. Call `LOAN.borrow(MO.balanceOf(UniV2Pair) - 1, 0)` to borrow nearly all MO from the pair.
5. Transfer 10 MO to the router, then swap 3 MO for USDT via `Router.swapExactTokensForTokens(3, 0, path, ...)`.
6. Observe USDT balance increase (~413k USDT profit).
**Exploitation:** Attacker used a flash-loan-like setup (via `deal` in PoC) to obtain a large MO balance, then repeatedly called borrow and redeem to manipulate the lending contract's accounting, ultimately borrowing almost all MO from the Uniswap V2 pair and swapping a tiny amount for USDT, draining the pair.
**Insight:** When a lending protocol allows borrow and redeem in the same transaction without proper state updates or cooldown, test looping these calls to see if the contract's internal accounting can be inflated or drained.
