The One With OTP but fake

The One With OTP but fake

Tags
Atropa
PulseChain
Python
Tutorial
Published
Published October 15, 2023
Last Updated
Last updated October 15, 2023
Description
シケイダ3301

Chapter 1 : Real Eyes

 
😈
So the first step is to thoroughly examine the contract, just as you would explore your girl.
We Used 👇
 
💡
byt3code uses the eth_getCode method of the RPC API to fetch the ByteCode of the ContractAddress. It then decodes the bytecode into a readable format using https://library.dedaub.com. You can explore byt3code source code at our GH page 😇

Chapter 2 : Realize

 
We read whole contract from here and differentiate the functions.
 

List of Basic Functions :

  • name()
  • approve(address,uint256)
  • totalSupply()
  • transferFrom(address,address,uint256) & transfer(address,uint256)
  • decimals()
  • balanceOf(address)
  • renounceOwnership()
  • owner()
  • burn(uint256) & burnFrom(address,uint256)
  • increaseAllowance(address,uint256) & decreaseAllowance(address,uint256) & allowance(address,address)
  • transferOwnership(address) & renounceOwnership()
 

We notice 3 Abnormal Functions

  • 0xb5095168
  • 0xd760dc8b
  • 0x3148f14f
 
function 0xb5095168() public payable { return stor_9; } // 0xb5095168 is returning stor_9 value.
function 0x3148f14f(uint256 varg0, uint256 varg1, uint256 varg2) public payable { require(4 + (msg.data.length - 4) - 4 >= 96); require(varg0 == varg0); require(varg1 == varg1); require(varg2 == varg2); MEM[MEM[64] + 96] = varg0; v0 = bigModExp(32, 32, v1, v1, varg1, varg2); require(v0); return MEM[MEM[192]]; } // the function 0x3148f14f is returning the result stored in MEM[MEM[192]]
function 0xd760dc8b(uint256 varg0) public payable { require(4 + (msg.data.length - 4) - 4 >= 32); require(varg0 == varg0); MEM[MEM[64] + 96] = stor_6; v0 = bigModExp(32, 32, v1, v1, stor_9, stor_8); require(v0); if (!(MEM[MEM[192]] - varg0)) { require(stor_7, Panic(18)); // division by zero stor_9 = keccak256(block.difficulty, block.timestamp) % stor_7; v2 = _SafeExp(10, uint8(18), uint256.max); require(!0x1 | (v2 == v2), Panic(17)); // arithmetic overflow or underflow require(msg.sender - address(0x0), Error('ERC20: mint to the zero address')); v3 = _SafeAdd(_totalSupply, v2); _totalSupply = v3; v4 = _SafeAdd(_balanceOf[msg.sender], v2); _balanceOf[msg.sender] = v4; emit Transfer(address(0x0), msg.sender, v2); } } // this function requires one uint256 valid OTP. it will mint one OTPF token. // we can see in function 0x3148f14f MEM[MEM[64] + 96] = varg0; and it is retrning MEM[MEM[64] + 96] // so we have to generate otp by providing three values to function 0x3148f14f // Namely : stor_6, stor_9, stor_8 // by looking at this function we can say stor_9 value is dynamic and changes after one time mint.
 
We can see below line from function 0x3148f14f.
v0 = bigModExp(32, 32, v1, v1, stor_9, stor_8);
😶
Now, we know varg1 and varg2 are stor_9and stor_8 in function 0x3148f14f
 
📢
By looking at code, Function 0xd760dc8b MEM[MEM[64] + 96] = stor_6 & Function 0x3148f14f MEM[MEM[64] + 96] = varg0 So by comparing both line we can say varg0 = stor_6

Chapter 3 : Real Lies

 
By looking at code, we can see
uint256 stor_6; // STORAGE[0x6] uint256 stor_8; // STORAGE[0x8] uint256 stor_9; // STORAGE[0x9]
 
 
  • Step 2: Call 0x3148f14f(stor_6, stor_9, stor_8) to generate OTP.
 
  • Step 3: Call 0xd760dc8b(OTP) to create Mint Transaction !
 

Step 1 : Getting Values

from web3 import Web3 from web3.middleware import construct_sign_and_send_raw_middleware from eth_account import Account RPC = "https://rpc.pulsechain.com" TARGET = "0x3815D67214216EC3683652c6f1DA4fD99F677d0b" w3 = Web3(Web3.HTTPProvider(RPC)) six = w3.eth.get_storage_at(TARGET, 0x6) eight = w3.eth.get_storage_at(TARGET, 0x8) nine = w3.eth.get_storage_at(TARGET, 0x9) call_data = six.hex()[2:] + nine.hex()[2:] + eight.hex()[2:]
Note: [2:} removes ‘0x’ from starting of each result.

Step 2 : Getting OTP

# continuation for step 1. call_data = six.hex()[2:] + nine.hex()[2:] + eight.hex()[2:] otp = w3.eth.call({"value": 0, "to": TARGET, "data": "0x3148f14f" + call_data})

Step 3 : Creating Mint

private_key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" # replace me account = Account.from_key(private_key) w3.middleware_onion.add(construct_sign_and_send_raw_middleware(account)) mint_call_data = "0xd760dc8b" + otp.hex()[2:] txn = w3.eth.send_transaction({"from": account.address, "value": 0, "to": TARGET, "data": mint_call_data}) print(f"created transaction : txn.hex()")
 
Hope we atleast pointed you to right direction.