Uji kode kontrak pintar Anda dengan ChatGPT dan Diligence Fuzzing

Uji kode kontrak pintar Anda dengan ChatGPT dan Diligence Fuzzing
ChatGPT luar biasa untuk menemukan bug tanpa memerlukan konteks tambahan yang signifikan di luar kode sumber. Ini menjadikannya tempat pertama yang bagus untuk memulai perjalanan pengujian Anda.
Salah satu hal pertama yang Anda pelajari sebagai pembuat kode kontrak cerdas adalah itu kontrak sangat kejam dalam hal kerentanan. Kontrak tidak dapat diubah secara default. Pada saat yang sama, mereka mampu mengelola uang dalam jumlah yang luar biasa. Hal ini membuat keamanan (dan pengujian kontrak pintar) menjadi perhatian terbesar dari tim pengembang Web3 mana pun.
Tetapi kontrak audit — garis pertahanan terakhir yang khas terhadap bug — selalu memakan waktu dan mahal. Untungnya, telah terjadi ledakan alat canggih yang membuat pengujian keamanan dan kontrak cerdas menjadi lebih murah, sederhana, dan lebih cepat.
Pada artikel ini, kita akan mengeksplorasi pengujian kontrak pintar menggunakan dua alat tersebut: ChatGPT oleh OpenAI dan Kereta Pos Fuzzing oleh ConsenSys.
Menguji kontrak pintar Ethereum dengan ChatGPT dan Diligence Fuzzing
Mari telusuri smart contract untuk proyek Ethereum yang memiliki kode ERC-20 yang rentan dan lihat apa yang dapat dilakukan kedua alat tersebut untuk kita.
Kereta Pos Fuzzing adalah alat ConsenSys yang mengimplementasikan fuzzing untuk web3. Fuzzing adalah teknik pengujian dinamis di mana input acak (atau semi-acak) yang disebut “fuzz” dihasilkan dan disuntikkan ke dalam kode. Fuzzing dapat membantu mengungkap bug dan kerentanan yang tidak terdeteksi oleh metode pengujian tradisional.
Dan tentu saja, ChatGPT adalah model bahasa besar (LLM) AI. Kecuali Anda pernah tinggal di bawah batu, Anda mungkin sudah familiar dengan ChatGPT dan beberapa fiturnya. Ini adalah salah satu teknologi paling menarik yang muncul dalam dekade terakhir. Tidak hanya dapat membantu Anda dalam pengujian (seperti yang akan kita lihat di artikel ini), tetapi juga dengan mengembangkan kontrak pintar, menulis tes, dan banyak lagi.
Ayo mulai!
Langkah 1: Instal Python, pip, npm, dan Node.js
Untuk menginstal alat yang diperlukan untuk menjalankan Diligence Fuzzing, pertama-tama Anda memerlukan yang berikut ini di mesin lokal Anda: versi terbaru dari Piton dan pip dan versi terbaru dari Node.js dan npm.
Verifikasi bahwa keempatnya berjalan menggunakan perintah ini:
$ node -v
$ npm -v
$ python –-version
$ pip --version
Langkah 2: Instal repositori kontrak yang rentan
Selain membuat Diligence Fuzzing dan bahasa anotasi Scribble, ConsenSys merilis sekumpulan repositori yang berisi kontrak yang rentan. Sederhananya, Anda akan menggunakan salah satunya.
Anda akan menggunakan repo yang berisi implementasi standar ERC-20 yang rentan (standar untuk cryptocurrency dan token yang dapat dipertukarkan).
Kloning repositori ini menggunakan perintah berikut:
$ git clone contracts-test
Repositori ini berisi folder bernama kontrak. Di dalam folder ini Anda akan menemukan sebuah file bernama rentanERC20.sol. Seperti disebutkan sebelumnya, file ini berisi implementasi standar ERC-20 yang cacat.
Ini adalah kontrak yang akan Anda uji menggunakan ChatGPT dan kemudian Diligence Fuzzing.
Langkah 3: Buat akun OpenAI
ChatGPT kebetulan sangat mahir dalam berbagai tugas, termasuk pengembangan Web3. (Lihat artikel saya sebelumnya tentang membuat kontrak pintar dengan ChatGPT.)
Anda dapat meminta ChatGPT untuk membongkar konsep blockchain yang rumit, menulis kontrak pintar yang mengimplementasikan sesuatu yang Anda pikirkan (misalnya lotre terdesentralisasi), atau bahkan memandu Anda melalui sepotong kode dan menemukan potensi kerentanan.
Seperti yang mungkin sudah Anda duga, fitur terakhir inilah yang menarik minat kami pada artikel ini.
Untuk mengakses ChatGPT, Anda harus buat akun OpenAI. Setelah Anda membuat akun, mengakses UI ChatGPT.
Berbicara dengan ChatGPT semudah berbicara dengan seseorang di aplikasi perpesanan. Jika ini adalah pertama kalinya Anda menggunakan alat ini, saya sangat menyarankan untuk menguji beberapa petunjuk sampel (mis. “Jelaskan komputasi kuantum dalam istilah awam”) untuk membiasakan diri.
Langkah 4: Periksa kerentanan dalam kontrak
Kunci untuk mendapatkan jawaban yang benar dari ChatGPT adalah dengan sangat jelas dan mendetail tentang permintaan Anda. Tempel prompt berikut ke UI:
Following is a smart contract I've written in Solidity. As a first step in testing its safety, I want you to examine the code, and let me know of all the security vulnerabilities that you find.
```
pragma solidity ^0.6.0;
contract VulnerableToken {
uint256 private _totalSupply;
mapping (address => uint256) private _balances;
mapping (address => mapping (address => uint256)) private _allowances;
constructor() public {
_totalSupply = 1000000;
_balances[msg.sender] = 1000000;
}
function totalSupply() external view returns (uint256) {
return _totalSupply;
}
function balanceOf(address _owner) external view returns (uint256) {
return _balances[_owner];
}
function allowance(address _owner, address _spender) external view returns (uint256) {
return _allowances[_owner][_spender];
}
function transfer(address _to, uint256 _value) external returns (bool) {
address from = msg.sender;
require(_value <= _balances[from]);
uint256 newBalanceFrom = _balances[from] - _value;
uint256 newBalanceTo = _balances[_to] + _value;
_balances[from] = newBalanceFrom;
_balances[_to] = newBalanceTo;
emit Transfer(msg.sender, _to, _value);
return true;
}
function approve(address _spender, uint256 _value) external returns (bool) {
address owner = msg.sender;
_allowances[owner][_spender] = _value;
emit Approval(owner, _spender, _value);
return true;
}
function transferFrom(address _from, address _to, uint256 _value) external returns (bool) {
uint256 allowed = _allowances[_from][msg.sender];
require(_value <= allowed);
require(_value <= _balances[_from]);
_balances[_from] -= _value;
_balances[_to] += _value;
_allowances[_from][msg.sender] -= _value;
emit Transfer(_from, _to, _value);
return true;
}
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}
```
ChatGPT akan memberi Anda respons yang terlihat seperti ini:
Upon reviewing the code, I have identified several security vulnerabilities and
concerns in the provided smart contract:
1. Lack of Access Control: The contract does not implement any access control
mechanism, allowing anyone to call the `transfer`, `approve`, and `transferFrom`
functions. This means that anyone can transfer tokens on behalf of another
address and modify allowances.
2. Integer Underflow and Overflow: The code uses basic arithmetic operations
without any checks for potential underflow or overflow. For example, in the
`transfer` and `transferFrom` functions, the subtraction and addition of token
balances can lead to unintended behavior if the resulting balance exceeds the
maximum value that can be stored in a `uint256`. You should include checks to
prevent these issues.
3. Lack of Require Statements for Input Validation: The contract lacks require
statements to validate inputs in various functions. For instance, in the
`transfer` and `transferFrom` functions, there is no validation to ensure
that the recipient address (`_to`) is not the zero address. Additionally,
the `approve` function does not validate that the spender address (`_spender`)
is not the zero address.
4. Potential Reentrancy Attacks: The contract is susceptible to reentrancy
attacks, where a malicious contract could repeatedly call the `transferFrom`
function to drain the token balance of another address. It is recommended to
use the "Checks-Effects-Interactions" pattern or implement a reentrancy guard
to mitigate this vulnerability.
5. Lack of Events for Critical State Changes: While the contract emits
`Transfer` and `Approval` events, it is missing events for critical state
changes, such as when the total supply is modified or token balances are
updated. Emitting events for these events helps provide transparency and
enables easier tracking of contract activities.
6. Fixed Token Supply: The contract initializes with a fixed token supply
of 1,000,000 tokens, and there are no provisions for minting or burning
tokens. If you intend to have a fixed supply, this may not be a vulnerability.
However, if you plan to have a dynamic token supply, you'll need to
implement minting and burning functions while considering proper access
control.
To enhance the security of your smart contract, consider addressing these
vulnerabilities and implementing additional security measures based on your
specific requirements.
ChatGPT memberi Anda banyak saran! Meskipun sebagian besar bersifat umum, namun tetap dapat membantu Anda mengungkap beberapa masalah utama.
Namun berhati-hatilah, dalam beberapa kasus, seperti saran tentang kontrol akses, itu salah. Dan percaya atau tidak, ChatGPT akhirnya melewatkan kesalahan paling parah dalam kontrak kami – sesuatu yang berkaitan dengan mentransfer token ke diri kami sendiri. Ini adalah kesalahan yang sangat bernuansa yang hanya bisa ditangkap oleh ChatGPT dengan petunjuk tambahan. (Catatan: Dengan petunjuk yang cukup, saya bisa mendapatkan ChatGPT untuk menemukan kesalahannya.)
Pelajaran utama di sini adalah bahwa ChatGPT dapat membantu proses debug, tetapi hanya sebagai titik awal. Setidaknya untuk saat ini, yang terbaik adalah mengidentifikasi kesalahan sintaksis, baik yang jelas maupun umum. Ini mungkin lebih berguna untuk pengembang pemula atau menengah, atau mungkin untuk senior yang lelah dan terlalu banyak bekerja! Untuk kasus yang lebih bernuansa, Anda harus beralih ke alat yang lebih canggih.
Langkah 5: Mendaftar untuk Diligence Fuzzing
Latihan di atas menunjukkan bahwa setidaknya pada saat penulisan (Juni 2023), ChatGPT dapat melakukan banyak hal, tetapi bukan pengganti yang lengkap untuk pengembang Web3 yang berpengalaman, terutama yang dapat memanfaatkan ‘canggih’. alat pengujian.
Pada langkah ini, Anda akan mempelajari cara menggunakan salah satu alat ini: Kereta Pos Fuzzing.
Seperti disebutkan di atas, fuzzing adalah teknik pengujian mapan yang melibatkan pengiriman data acak, sering salah, ke program tertentu dalam upaya untuk memicu perilaku atau crash yang tidak terduga. Metode ini terbukti sangat efektif dalam mendeteksi masalah keamanan yang sering dilewatkan oleh penguji tradisional.
Diligence Fuzzing menerapkan fuzzing tradisional di lingkungan web3. Alat ini dibuat untuk mendeteksi kerentanan kritis dan masalah tak terduga menggunakan anotasi sederhana di Scribble.
Untuk menggunakan alat ini, Anda harus terlebih dahulu Mendaftar untuk mendapatkan akun gratis dengan Diligence Fuzzing. Berlangganan ke tingkat gratis sudah lebih dari cukup untuk tutorial ini, tetapi jika Anda melakukan banyak pengujian kritis, pertimbangkan untuk meningkatkan ke tingkat berbayar.
Setelah Anda berlangganan, Anda akan melihat dasbor yang terlihat seperti ini.
Langkah 6: Buat Kunci API Diligence Fuzzing
Untuk mengakses fitur Diligence Fuzzing, Anda harus buat kunci API di sini.
Anda dapat memberi nama kunci Anda apa pun yang Anda inginkan. Jaga kerahasiaan kunci ini dan amankan. Anda akan membutuhkannya nanti.
Langkah 7: Instal paket dan pustaka yang diperlukan
Anda akan menginstal terlebih dahulu Truffle, Scribble, dan Fuzzing CLI di mesin lokal Anda. Jalankan perintah berikut:
$ cd contracts-test
$ npm install
$ npm install -g truffle eth-scribble ganache
$ pip3 install diligence-fuzzing
Langkah 8: Buat kampanye fuzzing
Arahkan ke folder contract-test yang telah Anda kloning sebelumnya. Buka repositori ini di editor kode favorit Anda (mis. VS Code) dan buka file bernama .fuzz.yml
. Anda akan melihat baris yang mengatakan kunci yang memiliki string kosong yang terkait dengannya. Ganti yang terakhir dengan kunci API Anda.
Agar Diligence Fuzzing berfungsi dengan baik, Anda harus membubuhi keterangan kontrak kami dengan peraturan yang menurut Anda harus Anda ikuti. Seperti disebutkan sebelumnya, bahasa anotasi di sini adalah gambar yg tak berarti.
Untuk tutorial ini, Anda tidak perlu tahu cara menulis Scribble sendiri (walaupun Anda harus meluangkan waktu sejenak untuk membiasakan diri dengan yang ini untuk proyek mendatang). Repositori yang Anda unduh datang (secara default) dengan kontrak beranotasi di folder kontrak/solusi. Anda akan menggunakan ini sebagai dasar untuk membubuhi keterangan kontrak yang rentan.
Ganti isi dari vulnerableERC20.sol
dengan berikut ini:
pragma solidity ^0.6.0;
contract VulnerableToken {
uint256 private _totalSupply;
mapping (address => uint256) private _balances;
mapping (address => mapping (address => uint256)) private _allowances;
constructor() public {
_totalSupply = 1000000;
_balances[msg.sender] = 1000000;
}
function totalSupply() external view returns (uint256) {
return _totalSupply;
}
function balanceOf(address _owner) external view returns (uint256) {
return _balances[_owner];
}
function allowance(address _owner, address _spender) external view returns (uint256) {
return _allowances[_owner][_spender];
}
/// #if_succeeds msg.sender != _to ==> _balances[_to] == old(_balances[_to]) + _value;
/// #if_succeeds msg.sender != _to ==> _balances[msg.sender] == old(_balances[msg.sender]) - _value;
/// #if_succeeds msg.sender == _to ==> _balances[msg.sender] == old(_balances[_to]);
/// #if_succeeds old(_balances[msg.sender]) >= _value;
function transfer(address _to, uint256 _value) external returns (bool) {
address from = msg.sender;
require(_value <= _balances[from]);
// _balances[from] -= _value;
// _balances[_to] += _value;
uint256 newBalanceFrom = _balances[from] - _value;
uint256 newBalanceTo = _balances[_to] + _value;
_balances[from] = newBalanceFrom;
_balances[_to] = newBalanceTo;
emit Transfer(msg.sender, _to, _value);
return true;
}
function approve(address _spender, uint256 _value) external returns (bool) {
address owner = msg.sender;
_allowances[owner][_spender] = _value;
emit Approval(owner, _spender, _value);
return true;
}
function transferFrom(address _from, address _to, uint256 _value) external returns (bool) {
uint256 allowed = _allowances[_from][msg.sender];
require(_value <= allowed);
require(_value <= _balances[_from]);
_balances[_from] -= _value;
_balances[_to] += _value;
_allowances[_from][msg.sender] -= _value;
emit Transfer(_from, _to, _value);
return true;
}
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}
Komentar pada baris 25 sampai 28 merupakan anotasi yang ditulis dengan Coretan. Bahkan jika Anda belum pernah mengenal bahasa ini sebelumnya, kontennya harus cukup jelas.
Kamu siap. Mulai fuzzing dengan menjalankan perintah berikut:
make fuzz
Ini akan meminta terminal Anda untuk menjalankan serangkaian perintah.
Perhatikan bahwa hasilnya juga berisi URL yang memberikan lebih banyak informasi tentang kampanye Anda.
Kampanye ini membutuhkan waktu sekitar lima menit untuk dijalankan. Namun begitu selesai, Anda mendapatkan laporan terperinci tentang temuannya, termasuk kerentanan.
Perhatikan bahwa di bagian Properti, laporan menunjukkan bahwa pernyataan pengguna gagal. Melihat lebih dekat, kita melihat bahwa ini adalah:
/// #if_succeeds msg.sender == _to ==> _balances[msg.sender] == old(_balances[_to]);
Anda dapat melihat detail transaksi untuk mempelajari lebih lanjut.
Pada dasarnya, ini memberi tahu Anda bahwa ada kerentanan ketika pengirim dan penerimanya sama!
Diligence Fuzzing melakukan pekerjaan yang bagus untuk tugas tertentu – ini secara otomatis membuat berbagai input untuk menghasilkan pengujian unit dan pengujian sistem yang menemukan bug dan kerentanan dalam kontrak cerdas Anda.
Buat plugin ChatGPT dan Diligence
Anda dapat melangkah lebih jauh dengan menggabungkan kekuatan kedua alat pengujian menggunakan plugin ChatGPT. Plugin ini dapat:
-
Jalankan kode untuk menginisialisasi kampanye Diligence Fuzzing terhadap kontrak
-
Menganalisis hasil dan menggunakannya untuk melakukan sesuatu yang menarik: menulis ulang kode secara langsung, menawarkan saran untuk perbaikan, menulis ulang dan menguji ulang kode secara otomatis hingga tidak ada lagi cacat yang ditemukan, dll.
Anda dapat gunakan titik awal ini untuk membuat plugin— atau dalam semangat artikel ini, bahkan minta ChatGPT menulis plugin untuk/bersama Anda!
Kesimpulan
Dalam tutorial ini, Anda menjelajahi dua alat yang sangat ampuh untuk pengujian kontrak cerdas dan audit keamanan.
ChatGPT luar biasa dalam menemukan bug tanpa memerlukan konteks tambahan yang signifikan di luar kode sumber. Ini menjadikannya tempat pertama yang bagus untuk memulai perjalanan pengujian Anda.
Namun, seperti yang telah Anda lihat, ChatGPT cenderung lepas kendali dan sering memberikan jawaban yang salah. Sebagai pengganti audit penuh, jalan masih panjang. Di sinilah alat seperti Diligence Fuzzing bisa bersinar. Ini mungkin memerlukan sedikit lebih banyak intervensi manual, tetapi jauh lebih komprehensif dalam hal cakupan.
Semoga harimu sangat menyenangkan !