

The source of the project is from:
https://github.com/PatrickAlphaC/smartcontract-lottery
https://www.youtube.com/watch?v=M576WGiDBdQ&t=22298s
The purpose of this walkthrough is to explain each part of the Smart Contract code with more context so that we can gain better understanding.
Think about the different processes for a lottery.
We need to create an address array to track down the participants. Before we add the new player to the participant list, they have to pay an entry fee. This entry fee is calculated based on current Ether price.
address payable[] public players;
function enter() public payable {
require(msg.value > getEntranceFee());
players.push(msg.sender);
}
We can use ChainLink price feed to get the latest Ether data. To do so, we need to specify the dependencies and remappings in brownie-config.yaml
file.
import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol";
[...]
AggregatorV3Interface internal ethUsdPriceFeed;
function getEntranceFee() public view returns (uint256) {
(, int256 price, , , ) = ethUsdPriceFeed.latestRoundData();
uint256 adjustedPrice = uint256(price) * 10**10;
uint256 costToEnter = (usdEntryFee * 10**18) / adjustedPrice;
return costToEnter;
}
pip install web3 py-solc-x
We are going to walkthrough a tutorial created by Patrick Collins (https://github.com/PatrickAlphaC/web3_py_simple_storage)
Create a new project folder and copy the sample solidity code to a new file SimpleStorage.sol
:
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.9.0;
contract SimpleStorage {
uint256 favoriteNumber;
// This is a comment!
struct People {
uint256 favoriteNumber;
string name;
}
People[] public people;
mapping(string => uint256) public nameToFavoriteNumber;
function store(uint256 _favoriteNumber) public {
favoriteNumber = _favoriteNumber;
}
function retrieve() public view returns (uint256) {
return favoriteNumber;
}
function addPerson(string memory _name, uint256 _favoriteNumber) public {
people.push(People(_favoriteNumber, _name));
nameToFavoriteNumber[_name] = _favoriteNumber;
}
}
Create a deploy.py
file. We are going to walkthrough step-by-step to understand each part of the code.
1. Import these required modules.
from solcx import compile_standard
from solcx import install_solc
import json
import os
from web3 import Web3
2. We use solcx
to compile the smart contract code. This is a python wrapper for the Solidity compiler.
First we open and read the content of the smart contract code.
Then install the solidity compiler version. It will download the compiler from the project’s Github download link.
Configure the compile standards:
We can dump the compiled code to see the structure of the code.
with open("./SimpleStorage.sol", "r") as file:
simple_storage_file = file.read()
print("Installing solc...")
install_solc('0.6.0')
# Configure compile standards
compiled_sol = compile_standard(
{
"language": "Solidity",
"sources": {"SimpleStorage.sol": {"content": simple_storage_file}},
"settings": {
"outputSelection": {
"*": {
"*": ["abi", "metadata", "evm.bytecode", "evm.bytecode.sourceMap"]
}
}
}
},
solc_version="0.6.0"
)
# Dump the compiled code to see the structure of the code
with open("compiled_code.json", "w") as file:
json.dump(compiled_sol, file)
3. Get the bytecode and abi from the compiled code. How do we know the structure of the JSON? Refer to the compiled_code.json
file
bytecode = compiled_sol["contracts"]["SimpleStorage.sol"]["SimpleStorage"]["evm"]["bytecode"]["object"]
abi = compiled_sol["contracts"]["SimpleStorage.sol"]["SimpleStorage"]["abi"]
4. Now start ganache server and we can see the generated dummy accounts and private keys. Note down where the server is listening.
$ ganache
ganache v7.0.2 (@ganache/cli: 0.1.3, @ganache/core: 0.1.3)
Starting RPC server
Available Accounts
==================
(0) 0xB136383615B477B1B816f4227A509ea8F0C0c9DD (1000 ETH)
(1) 0xB6c6BDb34A834BAcc8e07c9765E2f85D1619beDc (1000 ETH)
(2) 0xb2e141ed4EF4F30BC7a1848FFbd623b19B08608C (1000 ETH)
(3) 0x32c0DB620E7355feE0254813932a4E7a454D74f8 (1000 ETH)
(4) 0xB19D507aEE3BdA3c9da9b360E491B88FFd857f14 (1000 ETH)
(5) 0x7B0929a005B39Cce2C9795558371F3865Cff1Bf9 (1000 ETH)
(6) 0x13665EC9cEE2915402BD7Ce69c05F70E9CBCF2ef (1000 ETH)
(7) 0x2C2c3C4585c9425969C03055554dD0C15f5a57b8 (1000 ETH)
(8) 0xdAD8Ae2871Cb242C001A68EB5Bc6941BFDB0d2A7 (1000 ETH)
(9) 0x85214561dCD632581a0b60BeE5989607005BE663 (1000 ETH)
Private Keys
==================
(0) 0xa4c6bac88b45ba1e21eafbd736c92ca60b67bbfb956ccd3da37fa6f83ebe38c1
(1) 0xfa197f239d6df371b0242b8fe96b0d1883a392ff5ab4502cefae0e972f07f081
(2) 0x6c96d2d7b0fb9b56cad49887e3f198de2faa93d321240201d0572732f83bbcc8
(3) 0xd9eb1ec171c1aee37b0603b85d58b615d678f3f9c85c4e5fe31c322113d009d3
(4) 0xd6c212925da4e19a4708b43d1728efef1cf5c839fd44ee411107837b30d8e38c
(5) 0x048c50d14357791a5cbf1ecbf1febda6bf215f946bac50fac410524cde6cb397
(6) 0xb9eeb83abac9b23a5bc801e584c646f92ecb37cd4b7770100f84ea2ccdf3a304
(7) 0xad157fbf68f3e7fb3047ca653c073b4389f5020ce8d397c7c8f3533c491a15ba
(8) 0x01caede47d8ad5d0e5c125b9d4ceba7abd201a26be10730fc926f673f275fd42
(9) 0x07da7e22ff6a56ce2c07bf724913e507621181f369d481fd94ebb12d577d4650
HD Wallet
==================
Mnemonic: team shoot anchor limit inform imitate melody decrease wing sadness orange mammal
Base HD Path: m/44'/60'/0'/0/{account_index}
Default Gas Price
==================
2000000000
BlockGas Limit
==================
30000000
Call Gas Limit
==================
50000000
Chain Id
==================
1337
RPC Listening on 127.0.0.1:8545
5. Setup connection to the ganache server
w3 = Web3(Web3.HTTPProvider("http://127.0.0.1:8545"))
chain_id = 1337
my_addr = "0xB136383615B477B1B816f4227A509ea8F0C0c9DD"
private_key = os.getenv("PRIVATE_KEY")
DO NOT HARDCODE YOUR PRIVATE KEY IN YOUR CODE REPOS
If we want to connect to Testnet environment, we can use an ETH gateway such as Infura or Alchemy.
6a. Create the contract with the provider using the abi and bytecode.
SimpleStorage = w3.eth.contract(abi=abi, bytecode=bytecode)
6b. Get latest transaction count and use it as the nonce
nonce = w3.eth.getTransactionCount(my_addr)
6c. Submit the transaction that deploys contract using the chainId, gasPrice, from (which addr) and nonce
transaction = SimpleStorage.constructor().buildTransaction(
{
"chainId": chain_id,
"gasPrice": w3.eth.gas_price,
"from": my_addr,
"nonce": nonce
}
)
6d. Sign the transaction with private key
signed_txn = w3.eth.account.sign_transaction(transaction, private_key=private_key)
7. Deploy the contract
tx_hash = w3.eth.send_raw_transaction(signed_txn.rawTransaction)tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash)contract_addr = tx_receipt.contractAddressprint(f"Contract is deployed to {contract_addr}")
Since the Smart Contract is deployed, we can provide the contract address and abi to create the smart contract (“simple_storage”).
simple_storage = w3.eth.contract(address=contract_addr, abi=abi)
We can make a function call without changing any state in the smart contract. In this example, we are trying to retrieve the stored value in the smart contract.
print(f"Initial Stored Value = {simple_storage.functions.retrieve().call()}")
Now, we call the store
function in the smart contract to update favoriteNumber
variable.
greeting_transaction = simple_storage.functions.store(15).buildTransaction(
{
"chainId": chain_id,
"gasPrice": w3.eth.gas_price,
"from": my_addr,
"nonce": nonce + 1
}
)
We will sign this transaction with the private key, send the transaction to the Ganache server and then wait for the transaction receipt.
Notice if you execute the transaction in local blockchain VM, the transaction speed will be very fast. But in actual Testnet or Mainnet, the transaction is likely to be slower.
signed_greeting_txn = w3.eth.account.sign_transaction(greeting_transaction, private_key=private_key)
tx_greeting_hash = w3.eth.send_raw_transaction(signed_greeting_txn.rawTransaction)
tx_receipt = w3.eth.wait_for_transaction_receipt(tx_greeting_hash)
Let’s print the stored value and we can see it is changed to 15
print(simple_storage.functions.retrieve().call())
Usual steps of creating a Dockerfile of your application:
Dockerfile Instructions | Arguments |
FROM | Base Image or other Container Image |
RUN | 1. Passing commands (runs in shell) 2. Passing exec form: [“executable”, “p1”, “p2”] Execute command in a new layer. Examples: – Updating dependencies |
COPY | COPY is preferred to ADD as we know clearly that COPY will just copy files from local directory. ADD is useful if you wanna copy the content in a tar file. |
ENTRYPOINT | Define the command that will always be executed when the container starts. By default, Docker is using /bin/sh -c as the entrypoint. |
CMD | Define the arguments that will be appended to the ENTRYPOINT |
WORKDIR | Define where your commands should run. Saves the trouble of running to many cd ..... |
EXPOSE | Define the ports that a container listens. |
ENV | Setting environment variables that can be used in other instructions such as RUN |
FROM node:12-alpine
RUN apk add --no-cache python2 g++ make
EXPOSE 9091
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]
References:
Make sure the port publish setting (
https://stackoverflow.com/questions/66316400/cannot-reach-docker-container-port-not-bound-p
) is positioned before the image tag so that it can override the image default settings.
docker run -p 9091:9091 -t spring-boot-docker
References:
“…make sure that the constraint is not allowed to waste any time. Ever. It should never be waiting on other resource for anything, and it should always be working on the highest priority commitment the IT Operations organization has made to the rest of the enterprise. Always.”
The Phoenix project
The NUMBER ONE constraint in Security department is people.
It is unlikely we can hire enough people to match the number of developers and operations engineers.
The way to free up our constraint (people) is to try to automate as many tasks as possible so that the people can do the things that are unique and contextual.
Another way is to take a preventative approach by educating developers and ops engineers on best security practices that they need to follow (this means secure by defaults configurations, having documentation and guides). The famous Netflix’s paved roads….
any improvement not made at the constraint is just an illusion, yes?
The Phoenix project
In the security industry, we are lucky to have many hunters sharing their write-ups in public. To learn deeper from these write-ups, we should have some methodologies to extract knowledge from these experts.
Applied Cognitive Task Analysis (ACTA) is a methodology used by researchers to elicit knowledge from different domain experts. I think it is an interesting methodology to experiment with to see if we can extract knowledge in a structured way from the bug hunting experts.
Note: I will be experimenting with a few techniques from ACTA and adjusting it to secondary texts like bug write-ups, blogs, youtube videos, news, Github commits etc. instead of the interviews with experts.
The goal is to see the contrast between Novice bug hunters like me and Experts bug hunters and then use the learned knowledge to improve my own hunting methodology.
How do we trigger neuroplasticity?
Self-assessment
High Alert state
Low Alert state
Useful Heuristics
Diet
ssh james@[TARGET IP] -p 2222
Password: november16
Option 1: Sudo
I tried to sudo but the credentials for James doesn’t work.
Password: whenevernoteartinstant
Previously I have cracked the password for these users but the credentials does not work as well
james:$6$7GS5e.yv$HqIH5MthpGWpczr3MnwDHlED8gbVSHt7ma8yxzBM8LuBReDV5e1Pu/VuRskugt1Ckul/SKGX.5PyMpzAYo3Cg/:18464:0:99999:7:::
paradox:$6$oRXQu43X$WaAj3Z/4sEPV1mJdHsyJkIZm1rjjnNxrY5c8GElJIjG7u36xSgMGwKA2woDIFudtyqY37YCyukiHJPhi4IU7H0:18464:0:99999:7:::
szymex:$6$B.EnuXiO$f/u00HosZIO3UQCEJplazoQtH8WJjSX/ooBjwmYfEOTcqCAlMjeFIgYWqR5Aj2vsfRyf6x1wXxKitcPUjcXlX/:18464:0:99999:7:::
bee:$6$.SqHrp6z$B4rWPi0Hkj0gbQMFujz1KHVs9VrSFu7AU9CxWrZV7GzH05tYPL1xRzUJlFHbyp0K9TAeY1M6niFseB9VLBWSo0:18464:0:99999:7:::
muirland:$6$SWybS8o2$9diveQinxy8PJQnGQQWbTNKeb2AiSp.i8KznuAjYbqI3q04Rf5hjHPer3weiC.2MrOj2o1Sw/fd2cu0kC6dUP.:18464:0:99999:7:::
I tried to find the SUID binaries. There is one uncommon binary in /home/james/.suid_bash When I execute the binary, there is a bash running but the user was still james. But we can elevate the privilege but running with -p
That’s how we get the root user.