# -*- coding: utf-8 -*- class time_Obj(): def __init__(self,arrive,leave): self.arrive = arrive self.leave = leave if __name__ == "__main__": max = 0 #time_List 타임 리스트를 넣는 오브젝트 time_List = [] A,B,C = map(int, input().split(' ')) for i in range(3): at,lt = map(int ,input().split(' ')) if( max < lt ): max = lt time_List.append(time_Obj(at,lt)) time = 0 time_flow_q = [] value = 0 while(True): for time_Obj in time_List: if (time_Obj.arrive == time) : time_flow_q.append(time_Obj) for truck in time_flow_q : if( truck.leave == time ): time_flow_q.remove(truck) #현재 몇 개의 차가 주차되있느냐 #그에 따라 요금 부과 if (len( time_flow_q)== 1 ): value += A * 1 elif(len( time_flow_q) == 2 ): value += B * 2 elif (len( time_flow_q) == 3 ): value += C * 3 #시간 flow time += 1 if( len(time_flow_q) == 0 and time > max ): break print(value)


# 상근이는 트럭을 총 세 대 가지고 있다. 오늘은 트럭을 주차하는데 비용이 얼마나 필요한지 알아보려고 한다.

# 상근이가 이용하는 주차장은 주차하는 트럭의 수에 따라서 주차 요금을 할인해 준다.

# 트럭을 한 대 주차할 때는 1분에 한 대당 A원을 내야 한다. 

#두 대를 주차할 때는 1분에 한 대당 B원, 

#세 대를 주차할 때는 1분에 한 대당 C원을 내야 한다.

# A, B, C가 주어지고, 상근이의 트럭이 주차장에 주차된 시간이 주어졌을 때, 주차 요금으로 얼마를 내야 하는지 구하는 프로그램을 작성하시오.

# 첫째 줄에 문제에서 설명한 주차 요금 A, B, C가 주어진다. (1 ≤ C ≤ B ≤ A ≤ 100)

# 다음 세 개 줄에는 두 정수가 주어진다. 

# 이 정수는 상근이가 가지고 있는 트럭이 주차장에 도착한 시간과 주차장에서 떠난 시간이다. 

# 도착한 시간은 항상 떠난 시간보다 앞선다. 

# 입력으로 주어지는 시간은 1과 100사이 이다.

# 5 3 1

# 1 6

# 3 5

# 2 8




오랜만에 푼 문제 


문제에서 설명해준 대로 코드를 작성하면 된다


자그마치 8개월전에 도전했다가 런타임에러로 못풀었던 문제인데


코드를 보니 그게 더  깔끔하고 효율적이더라


..퇴보했다..ㅜㅜ..

블로그 이미지

알파세




해당 컨트랙트에 Deposit 함수를 사용하여 계약 주소를

충전한 후 send()를 사용하여 계약 주소를 전송합니다


여기서 전송결과는 false라는 사실을 확인 할 수 있다.


즉 악의적인 컨트랙트로 이러한 기능을 보낼때 수신자가 컨트랙트이므로 계약서에 

폴백 기능이 있어야 한다.

그러한 기능이 없는 경우 컨트랙트는 정기적인 거래를 통해 ether를 받을 수 없다 


폴백기능

이더를 수신하려면 fallback 기능을 표시행헌더,

payable 

없다 


Contracts that receive Ether directly (without a function call, i.e. using send or transfer) but do not define a fallback function throw an exception, sending back the Ether (this was different before Solidity v0.4.0). So if you want your contract to receive Ether, you have to implement a fallback function.

경고 - 

ether를 직접 받는 (즉 함수 호출없이 send 또는 transfer을 사용하는 ) fallback 함수를 정의하지 않고 ether를 받는 계약은 계약서에 ether를 받기 위해선 대체 기능을 만들어야한다 .






여기서 반환체크가 수행되지 않으므로 

다음 줄의 코드가 계속 되고

최종 금액은 이전되지 않았으나 잔액이 차감되게 됩니다.



취약점 방어 방법 -

또는 취약한 함수 send를 사용하지 않고 

transfer 함수를 통하여 롤백시킨다 . 




블로그 이미지

알파세

function transferProxy(address _from, address _to, uint256 _value, uint256 _feeSmt,
	uint8 _v,bytes32 _r, bytes32 _s) public transferAllowed(_from) returns (bool){

	if(balances[_from] < _feeSmt + _value) revert();

	uint256 nonce = nonces[_from];
	bytes32 h = keccak256(_from,_to,_value,_feeSmt,nonce);
	if(_from != ecrecover(h,_v,_r,_s)) revert();

	if(balances[_to] + _value < balances[_to]
		|| balances[msg.sender] + _feeSmt < balances[msg.sender]) revert();
	balances[_to] += _value;
	Transfer(_from, _to, _value);

	balances[msg.sender] += _feeSmt;
	Transfer(_from, msg.sender, _feeSmt);

	balances[_from] -= _value + _feeSmt;
	nonces[_from] = nonce + 1;
	return true;
}

문제가 되는 SmartMesh 스마트 컨트랙트의 transferProxy 함수를 살펴보도록 한다.

if(balances[_from] < _feeSmt + _value) revert();



이 함수에서 문제가 되는 함수는 _from 주소가 가지고 있는 토큰의 양보다 

_feeSmt , _value 값이 크면 전송을 중단하는 제어문을 가지고 있었으나


uint256에 덧셈에 대한 Overflow 처리가 안되있었다. 

uint는 이더리움이 표기하는 unsinged int의 변수 생성자 명인데 

뒤에 숫자값은 256bit란 얘기이다 

즉 최대값은 2^256-1 값이되나 여기서 1을 더하게 되면 

그 이상을 표기하지 못하고 0을 표현하게 되버리는 것이다 .





overflow가 발생한다면 실제 결과값은 작은 숫자가 되어

해당 함수를 넘어가 트랜잭션이 발생할수 있다는 것을 포착해 

해커는 그 것을 이용하여  약 1경개의 코인을 자신의 erc 지갑으로 입금하였다 . 





해결방안 

SafeMath 라는 Zeppine사에서 만든 해결방안을 이용한다.

해당 취약점은 블록체인, 이더리움 자체의 문제가 아니라 

개발자의 코딩버그이다 ,



개요 

 smt코인의 총발행량 31억개보다 

1경개의 코인이 후오비 ERC 지갑으로 입금되는걸 포착하였다 . 

Apr-24–2018 07:16:19 PM +UTC 



해커가 발생시킨 트랜잭션을 살펴보자면 

[2] 에 해당하는 값이_value 값이고 

[3] 에 해당하는 값이 _feeSmt 이다

해커는 해당 토큰은 0개 가지고 있었고 

[2]에 해당하는 값과 [3]에 해당하는 값을 더하면 

overflow가 발생하게 위애서 서술했듯이 0이 되버리는 것이다.

해커는 결론적으로 엄청난 토큰을 자신에게 전송 할 수 있었다.



블로그 이미지

알파세