code4rena-2023-09-centrifuge-m06
[M-06] DelayedAdmin Cannot PauseAdmin.removePauser
Summary
문서에서는 DelayedAdmin 컨트랙트가 PauseAdmin 컨트랙트의 removePauser 함수를 호출하여 비상 상황에 대비할 수 있다고 했지만 실제로는 이를 호출하는 함수가 없었다.
Keyword
logic flaw
Vulnerability
오딧팅 레포지토리의 README에서 다음과 같은 비상 상황 대처 시나리오를 설명한다.
**Someone controls 1 pause admin and triggers a malicious `pause()`**
* The delayed admin is a `ward` on the pause admin and can trigger `PauseAdmin.removePauser`.
* It can then trigger `root.unpause()`.
pause 관리자(pausers)는 여러 계정이 등록될 수 있다. 이 중 한 계정이 해킹을 당해 악의적으로 pause()를 호출한 상황을 생각해보자.
DelayedAdmin 컨트랙트는 PauseAdmin 컨트랙트의 관리자이며 PauseAdmin.removePauser() 를 호출하여 악의적인 계정을 pausers에서 제외할 수 있다. 또한 DelayedAdmin은 root.unpause()를 호출하여 거래 정지를 다시 해제할 수 잇다.
하지만 문서에서 설명하는 것과는 달리, 실제 DelayedAdmin는 PauseAdmin.removePauser()를 호출할 수 없다. 다음은 DelayedAdmin 컨트랙트이다. DelayedAdmin 컨트랙트에는 PauseAdmin.removePauser()를 호출하는 함수가 없다.
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.21;
import {Root} from "../Root.sol";
import {Auth} from "./../util/Auth.sol";
/// @title Delayed Admin
/// @dev Any ward on this contract can trigger
/// instantaneous pausing and unpausing
/// on the Root, as well as schedule and cancel
/// new relys through the timelock.
contract DelayedAdmin is Auth {
Root public immutable root;
// --- Events ---
event File(bytes32 indexed what, address indexed data);
constructor(address root_) {
root = Root(root_);
wards[msg.sender] = 1;
emit Rely(msg.sender);
}
// --- Admin actions ---
function pause() public auth {
root.pause();
}
function unpause() public auth {
root.unpause();
}
function scheduleRely(address target) public auth {
root.scheduleRely(target);
}
function cancelRely(address target) public auth {
root.cancelRely(target);
}
}Impact
응급 상황에 빠르게 대처하지 못한다.
Mitigation
DelayedAdmin 컨트랙트에 PauseAdmin.removePauser() 를 호출하는 함수를 추가한다.
tags: bughunting, centrifuge, smart contract, solidity, logic flaw, severity medium