Skip to content

Commit

Permalink
Update 2024-09-15-Pike-Finance-Exploit-분석.md
Browse files Browse the repository at this point in the history
  • Loading branch information
bshyuunn authored Oct 15, 2024
1 parent 592068b commit 73ecf71
Showing 1 changed file with 24 additions and 23 deletions.
47 changes: 24 additions & 23 deletions _posts/2024-09-15-Pike-Finance-Exploit-분석.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,30 +23,28 @@ Pike Finance는 탈중앙화 금융(DeFi) 플랫폼으로, 다양한 블록체

Pike Finance Exploit의 TxHash는 다음과 같다. 해당 공격은 2024년 4월 30일 10:19:11 PM UTC에 발생했다. `0xe2912b8bf34d561983f2ae95f34e33ecc7792a2905a3e317fcc98052bce66431`

대부분의 체인에는 탐색기가 존재한다. 이더리움의 경우 **etherscan**이라는 블록 탐색기가 존재하고 이를 통해 해당 Tx에 대한 간단한 정보들을 수집할 수 있다. [[eterscan 링크]](https://etherscan.io/tx/0xe2912b8bf34d561983f2ae95f34e33ecc7792a2905a3e317fcc98052bce66431)
대부분의 체인에는 탐색기가 존재한다. 이더리움의 경우 etherscan이라는 블록 탐색기가 존재하고 이를 통해 해당 Tx에 대한 간단한 정보들을 수집할 수 있다. [[eterscan 링크]](https://etherscan.io/tx/0xe2912b8bf34d561983f2ae95f34e33ecc7792a2905a3e317fcc98052bce66431)

```
- From: 0x19066f7431df29A0910d287C8822936Bb7D89E23 **(Attacker)**
- To: 0x1da4bc596bfb1087f2f7999b0340fcba03c47fbd **(Attack Contract)**
- From: 0x19066f7431df29A0910d287C8822936Bb7D89E23 Attacker)
- To: 0x1da4bc596bfb1087f2f7999b0340fcba03c47fbd Attack Contract)
- Transfer: 479.393838338750964434 ETH
- Transfer from: 0xfc7599cffea9de127a9f9c748ccb451a34d2f063 **(Vulnerable Contract)**
- To: 0x19066f7431df29A0910d287C8822936Bb7D89E23 **(Attacker)**
- Transfer from: 0xfc7599cffea9de127a9f9c748ccb451a34d2f063 (Vulnerable Contract)
- To: 0x19066f7431df29A0910d287C8822936Bb7D89E23 (Attacker)
- Input Data: 0xf2afdff3 함수 호출
```

추가로 강력한 트랜잭션 뷰어인 **phalcon** 이용하여 트랜잭션에 대한 자세한 정보들을 쉽게 수집할 수 있다.[[phalcon 링크]](https://app.blocksec.com/explorer/tx/eth/0xe2912b8bf34d561983f2ae95f34e33ecc7792a2905a3e317fcc98052bce66431?line=9)
추가로 강력한 트랜잭션 뷰어인 phalcon을 이용하여 트랜잭션에 대한 자세한 정보들을 쉽게 수집할 수 있다.[[phalcon 링크]](https://app.blocksec.com/explorer/tx/eth/0xe2912b8bf34d561983f2ae95f34e33ecc7792a2905a3e317fcc98052bce66431?line=9)

먼저 State Changes된 값을 한눈에 확인할 수 있다.

![Untitled](https://prod-files-secure.s3.us-west-2.amazonaws.com/695efec6-e972-4a99-be64-e4ddaaa333ed/8e6f8f9e-c0aa-4837-acae-732df3a23f23/Untitled.png)
![image](https://github.com/user-attachments/assets/579412eb-0672-4dfc-93d9-47760dc61f32)

익스플로잇 트랜잭션에서 공격받은 컨트랙트 0xfc7599cffea9de127a9f9c748ccb451a34d2f063에서 State 변화가 발생했으며, EIP1967 Logic Contract 주소가 Attack Contract인 0x1da4bc596bfb1087f2f7999b0340fcba03c47fbd로 변경된 것을 확인할 수 있다. (phalcon의 경우 어떤 슬롯에 어떤 데이터가 저장되어 있는지를 보고 어떤 EIP를 따르고 있는지 자동으로 분석해준다.)

이를 통해 Logic 주소 재정의를 통해 모든 자금을 드레인한 것으로 예상할 수 있다. 또한 0xb30c120Eb92c120bF11B358b4B9961E6679b6ae7 주소가 기존의 logic Contract임을 알 수 있다.

그리고 Invocation Flow를 통해 트랜잭션의 호출 흐름을 시각화해서 볼 수 있다.

![Untitled](https://prod-files-secure.s3.us-west-2.amazonaws.com/695efec6-e972-4a99-be64-e4ddaaa333ed/2c338c3c-3ee3-4986-9f62-7120e4bb2766/Untitled.png)
![image](https://github.com/user-attachments/assets/40f64c53-4e18-444f-a3b4-3426a9ffd985)

Invocation Flow를 보면 예상대로 `initialize` 함수를 통해 새로운 logic Contract를 정의해주고 있고 `ugradeToAndCall` 함수를 통해 새로운 logic contract로 업그레이드함과 동시에 모든 자금을 Attack Address로 보내고 있다.

Expand All @@ -58,7 +56,7 @@ Invocation Flow를 보면 예상대로 `initialize` 함수를 통해 새로운 l
| Vulnerable Contract | 0xfc7599cffea9de127a9f9c748ccb451a34d2f063 |
| Logic Contract | 0xb30c120Eb92c120bF11B358b4B9961E6679b6ae7 |

### 02.2 **루트 커즈 분석**
### 02.2 루트 커즈 분석

Vulnerable Contract와 Logic Contract 둘 다 contract code가 etherscan에 공개되어 있지 않다. 이 경우 Bytecode를 해석해야한다.

Expand Down Expand Up @@ -91,7 +89,7 @@ function function_selector() public payable {
}
```

다음으로 Logic Contract 중 공격자가 가장 먼저 호출한 함수인 `initialize`의 디컴파일된 모습이다. `initialize` 함수는 contract를 처음 초기화하는 역할을 한다. 해당 함수를 통해 공격자는 **_isActive** 값을 자신이 생성한 악성 contract로 설정할 수 있다.
다음으로 Logic Contract 중 공격자가 가장 먼저 호출한 함수인 `initialize`의 디컴파일된 모습이다. `initialize` 함수는 contract를 처음 초기화하는 역할을 한다. 해당 함수를 통해 공격자는 _isActive 값을 자신이 생성한 악성 contract로 설정할 수 있다.

```solidity
function initialize(address _console, address _rng, address _vault, address _gameProvider, uint16 _minPos, uint16 _maxPos) public nonPayable {
Expand All @@ -115,7 +113,7 @@ function initialize(address _console, address _rng, address _vault, address _gam
owner_2_0_19 = _rng;
_endpoint = _vault;
stor_4_0_19 = _gameProvider;
**_isActive** = 0x1 | (bytes31(msg.sender << 40) | 0xffffffffffffff0000000000000000000000000000000000000000ffffffff00 & (_maxPos << 24 | (0xffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffff & _minPos << 8 | _isActive & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ff)));
_isActive = 0x1 | (bytes31(msg.sender << 40) | 0xffffffffffffff0000000000000000000000000000000000000000ffffffff00 & (_maxPos << 24 | (0xffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffff & _minPos << 8 | _isActive & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ff)));
_nativeAsset = 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee;
if (!_initialize) {
_initialize = 0;
Expand All @@ -124,7 +122,7 @@ function initialize(address _console, address _rng, address _vault, address _gam
}
```

이후 공격자는 `upgradeToAndCall` 함수를 통해 logic contract를 악의적으로 **_isActive 값으로** 업그레이드하고 악성 행동을 수행할 수 있다.
이후 공격자는 `upgradeToAndCall` 함수를 통해 logic contract를 악의적으로 _isActive 값으로 업그레이드하고 악성 행동을 수행할 수 있다.

```solidity
function upgradeToAndCall(address newImplementation, bytes data) public payable {
Expand All @@ -148,19 +146,17 @@ function upgradeToAndCall(address newImplementation, bytes data) public payable

Vulnerable Contract를 처음 생선한 트랜젝션을 보면, Contract를 생성하는 동시에 `initialize` 함수를 호출하여 적절히 초기화하고 있다. 따라서, 원칙적으로 공격자는 initialize 함수를 다시 호출할 수 없다.

![https://app.blocksec.com/explorer/tx/eth/0x0fcc85422e9726a5d8b2ce00291051df0167089e0d1a5e66bfac908c0769e05d](https://prod-files-secure.s3.us-west-2.amazonaws.com/695efec6-e972-4a99-be64-e4ddaaa333ed/58348a9b-9ad4-4dbf-a15f-ddba6f78dfdb/Untitled.png)
![image](https://github.com/user-attachments/assets/63a4d4fb-c7d8-4ddc-aab0-d3efcb797749)

https://app.blocksec.com/explorer/tx/eth/0x0fcc85422e9726a5d8b2ce00291051df0167089e0d1a5e66bfac908c0769e05d

그러면 해당 문제는 왜 발생했을까?
그러면 해당 취약점은 왜 발생했을까?

### 02.3 왜 이런 일이 일어났을까?

`initialize` 함수를 한번 더 호출할 수 있는 이유는 Contract를 Upgrade하면서 발생한 storage misalignment 문제 때문이다.

PikiFinace는 해당 공격이 발생하기 몇일 전 공격을 받았고 이를 조사하기 위해 Contract를 Pause하고자 하였다. 하지만 Vulnerable Contract에는 해당 기능이 구현되어 있지 않아 Logic Contract 업그레이드를 진행했다. 이더스캔의 Event 탭을 통해 어떻게 Logic Contract가 어떻게 Upgrade 됬는지 확인할 수 있다.

![Untitled](https://prod-files-secure.s3.us-west-2.amazonaws.com/695efec6-e972-4a99-be64-e4ddaaa333ed/64a9a2d4-207f-488b-9a4c-890fbf5ed1a2/Untitled.png)
![image](https://github.com/user-attachments/assets/b5926410-62d1-4678-b524-95283b52dc60)

| Logic Contract 분류 | 주소 |
| --- | --- |
Expand All @@ -170,17 +166,19 @@ PikiFinace는 해당 공격이 발생하기 몇일 전 공격을 받았고 이

각 Contract에 어떠한 변화가 있는지 디컴파일한 후 확인해보자. 먼저 기존 Contract의 Data structures를 보면 다음과 같다.

![Untitled](https://prod-files-secure.s3.us-west-2.amazonaws.com/695efec6-e972-4a99-be64-e4ddaaa333ed/3397ffa6-ce10-450c-9911-59ac4aa19049/Untitled.png)
![image](https://github.com/user-attachments/assets/17019b62-9160-405f-820c-acca8ba40632)


다음은 Pause 기능이 추가된 Contract의 Data structures이다. 11번째 줄에 pause 기능을 지원하는 변수가 추가된 것을 볼 수 있다.

![Untitled](https://prod-files-secure.s3.us-west-2.amazonaws.com/695efec6-e972-4a99-be64-e4ddaaa333ed/655f0fc7-86bd-4aaf-9120-52d7ebd42064/Untitled.png)
![image](https://github.com/user-attachments/assets/4dd81833-c447-4606-941d-00e1478e19d6)


하지만 여기서 `_paused` 변수가 `STORAGE[0xb]의 bytes 0 to 0`에 위치하게 되면서 초기화 상태를 정의하는 변수인 `_initialize``STORAGE[0xb]의 bytes 1 to 1`에서 `STORAGE[0xb]의 bytes 2 to 2`로 변경되었다. 이로 인해 Contract의 초기화 상태를 정의하는 `_initialize` 변수가 0의 값을 가지게 된다.

공경 당한 Logic Contract에서도 여전히 같은 문제가 존재한다.
![image](https://github.com/user-attachments/assets/059fb707-a720-4736-b373-68ab3a93a14e)

![Untitled](https://prod-files-secure.s3.us-west-2.amazonaws.com/695efec6-e972-4a99-be64-e4ddaaa333ed/bc275a14-8fd4-43c4-bf01-d91f0b46816e/Untitled.png)

결과적으로 계약이 초기화되지 않은 상태로 잘못 인식되게 되고 공격자가 한번 더 `initialize` 함수를 호출할 수 있게 된다. 즉 pause 기능을 제공하는 새로운 라이브러리를 추가하는 과정에서 storage layout이 변경되는 것을 고려하지 못한 탓에 해당 취약점이 발생했다.

Expand All @@ -194,6 +192,8 @@ Storage misalignment과 같은 storage layout 관련된 오류를 막기 위해

이 외에도, namespaced storage layout을 활용할 수 있다. Namespaced storage layout은 각 컨트랙트가 고유의 네임스페이스를 사용하여 상태 변수를 저장하는 방식이다. 이를 통해 변수 간의 충돌을 방지하고, 각 컨트랙트의 상태 변수를 독립적으로 관리할 수 있다.

<br>

## 04. PoC를 통한 취약점 재현

foundry를 이용하여 PoC 코드를 작성할 수 있다.
Expand Down Expand Up @@ -273,7 +273,7 @@ contract Exploit is Test {
}
```

**실행 결과**
실행 결과

```bash
➜ PikeFinance_2024-04 git:(master) ✗ forge test --mc Exploit -vvvv
Expand Down Expand Up @@ -324,6 +324,7 @@ Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 424.12ms (1.11ms CP

Ran 1 test suite in 969.87ms (424.12ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)
```
<br>

## 05. Reference

Expand Down

0 comments on commit 73ecf71

Please sign in to comment.