diff --git a/.gitignore b/.gitignore index adf8f72..196a142 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ # Go workspace file go.work +traffic_dumps/ \ No newline at end of file diff --git a/CA.crt b/CA.crt new file mode 100644 index 0000000..231ed63 --- /dev/null +++ b/CA.crt @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIFOTCCBCGgAwIBAgIGAZi8TmIsMA0GCSqGSIb3DQEBCwUAMIGgMTEwLwYDVQQDDChDaGFybGVz +IFByb3h5IENBICgxOCBBdWcgMjAyNSwgQkxBQ0stUEMpMSUwIwYDVQQLDBxodHRwczovL2NoYXJs +ZXNwcm94eS5jb20vc3NsMREwDwYDVQQKDAhYSzcyIEx0ZDERMA8GA1UEBwwIQXVja2xhbmQxETAP +BgNVBAgMCEF1Y2tsYW5kMQswCQYDVQQGEwJOWjAeFw0yNTA4MTcwODMxNTBaFw0yNjA4MTcwODMx +NTBaMIGgMTEwLwYDVQQDDChDaGFybGVzIFByb3h5IENBICgxOCBBdWcgMjAyNSwgQkxBQ0stUEMp +MSUwIwYDVQQLDBxodHRwczovL2NoYXJsZXNwcm94eS5jb20vc3NsMREwDwYDVQQKDAhYSzcyIEx0 +ZDERMA8GA1UEBwwIQXVja2xhbmQxETAPBgNVBAgMCEF1Y2tsYW5kMQswCQYDVQQGEwJOWjCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKEmwh2Lk0017ak2c+3eKUGRsZVc5TSfcFaaiAk5 +kKMWj0pIXNKo2G8eERo4BYNqZi+icHGWBwmhAuUDJqpZMji2Qzv0jvuFDw0+UVVtp30RU/92GZYV +C44df+qPTYqUuD+ZPKdlo2RZ38Jbru/VT7AQQ53cvcBJ6s7WzY9QQVui1Rd3jHRXnyb9/duccw22 +vo6f2/OX2mVEKpXd5/3g8d+D8EuoiTUKDbgM39diOYuelh8Xybf0Zy1ZU4nkYeaVwzf9djlgxa1E +2Qb9SscxddGBJxyTrqtoG4ZLwzuwz3DX6KOEPX73I0Q8L+TBf7KQhBYkHSOa6HygE0Vgi3HoM4UC +AwEAAaOCAXUwggFxMA8GA1UdEwEB/wQFMAMBAf8wggEtBglghkgBhvhCAQ0EggEeE4IBGlRoaXMg +cm9vdCBjZXJ0aWZpY2F0ZSB3YXMgZ2VuZXJhdGVkIGJ5IENoYXJsZXMgUHJveHkgZm9yIFNTTCBQ +cm94eWluZy4gSWYgdGhpcyBjZXJ0aWZpY2F0ZSBpcyBwYXJ0IG9mIGEgY2VydGlmaWNhdGUgY2hh +aW4sIHRoaXMgbWVhbnMgdGhhdCB5b3UncmUgYnJvd3NpbmcgdGhyb3VnaCBDaGFybGVzIFByb3h5 +IHdpdGggU1NMIFByb3h5aW5nIGVuYWJsZWQgZm9yIHRoaXMgd2Vic2l0ZS4gUGxlYXNlIHNlZSBo +dHRwczovL2NoYXJsZXNwcm94eS5jb20vc3NsIGZvciBtb3JlIGluZm9ybWF0aW9uLjAOBgNVHQ8B +Af8EBAMCAgQwHQYDVR0OBBYEFKBf+QLehq0dc4s7YMIUUFJdgWBfMA0GCSqGSIb3DQEBCwUAA4IB +AQBc+K3gGnz00yv2XMYRMbeYLr3SD15Tx3NAPri08EY1wyyufkBCaI81tZSCMy4PkGAYN+zODrQ6 +MRj0tbABTNZHdzFCuazE+B2ce2Ka3PcQ1DNpGf60NYk9qBHpOxak+5XxrECFYjStYW3gLZ7mZSnI +YX9doSujRpzSbVZFvVh4J1zCzF1NuD6VxxfFjppJ6EnvnSSQOly0e32NzibQi3akFb4E5hn58py/ +Eth3xl7mzWjcdKeKd30TAeg98PA+drJ8JsunIc2sICcNuAoVSKQEX4ihZHMhFLXl0MNdyWQtqHPR +beQU9SvWF3DVmilrNO1neetL2TCZK5iMyIAHvqPo +-----END CERTIFICATE----- diff --git a/README.md b/README.md index 0976269..36f3b1e 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,167 @@ -# mitm +# MITM Proxy Server +This is a Man-in-the-Middle (MITM) proxy server written in Go, similar to the functionality of Charles proxy tool. + +## Features + +1. **Transparent MITM Proxy**: Completely transparent HTTP/HTTPS proxy that doesn't interfere with any traffic +2. **Hardcoded Certificates**: P12 certificate and CA certificate directly embedded in the program, no external files needed +3. **HTTPS Decryption**: Attempts to decrypt HTTPS traffic for inspection, falls back to transparent mode if decryption fails +4. **Dual Traffic Dump**: Save both encrypted and decrypted data to different files for analysis +5. **Complete Data Output**: Console displays complete request/response data without truncation +6. **Domain Filtering**: Print specific traffic to stdout based on the list of domains of interest in TOML configuration file +7. **System Proxy**: Automatically set Windows system proxy, restore when program ends +8. **CA Certificate Installation**: Automatically import hardcoded CA certificate to Windows trusted root certificate authorities +9. **Redirect Transparency**: All HTTP redirects (301/302/etc.) are passed through exactly as-is without modification +10. **Built-in Testing**: Use `-test` flag to verify proxy functionality and connectivity + +## Prerequisites + +1. **Go 1.21+**: Ensure Go language environment is installed +2. **OpenSSL**: For processing P12 certificate files (optional, will use basic configuration if not available) +3. **Administrator Privileges**: Setting system proxy and installing certificates requires administrator privileges + +## Installation and Usage + +### 1. Clone or Download Project + +```bash +git clone +cd mitm +``` + +### 2. Install Dependencies + +```bash +go mod tidy +``` + +### 3. Prepare Certificate Files + +Ensure you have the following files: +- `cert.p12`: P12 certificate file containing CA and private key +- `CA.crt`: CA certificate file + +### 4. Configuration File + +Edit the `config.toml` file: + +```toml +# Domains of interest configuration +domains_of_interest = [ + "example.com", + "httpbin.org", + "api.github.com", + "www.google.com" +] + +[proxy] +port = 8080 +cert_file = "cert.p12" +cert_password = "your_password_here" # Change to your certificate password +ca_cert_file = "CA.crt" + +[dump] +output_dir = "traffic_dumps" +``` + +### 5. Run Program + +**Important**: Need to run as administrator: + +```bash +# Open PowerShell or Command Prompt as administrator +go run . +``` + +Or compile and run: + +```bash +go build -o mitm.exe +# Run as administrator +./mitm.exe +``` + +## Usage Instructions + +1. **Start Program**: The program will automatically: + - Install CA certificate to system trusted root certificate store + - Set system proxy to `127.0.0.1:8080` + - Start proxy server + +2. **Traffic Interception**: + - All HTTP/HTTPS traffic will be intercepted **transparently** + - No modification of requests, responses, or redirects + - Each request will be saved to `traffic_dumps` directory + - Traffic from domains of interest will be printed to console + - HTTPS traffic is decrypted when possible, falls back to encrypted passthrough + +3. **Testing Connectivity**: + ```bash + # Test proxy functionality + go run . -test + ``` + +4. **Stop Program**: + - Press `Ctrl+C` to stop program + - Program will automatically restore original system proxy settings + +## File Structure + +``` +mitm/ +├── main.go # Main program file +├── cert_utils.go # Certificate processing tools +├── config.toml # Configuration file +├── go.mod # Go module file +├── cert.p12 # P12 certificate file (you need to provide) +├── CA.crt # CA certificate file (you need to provide) +└── traffic_dumps/ # Traffic dump directory (auto-created) +``` + +## Output File Format + +### HTTP Traffic Files +Filename format: `YYYYMMDD_HHMMSS_domain.txt` + +Content includes: +- Request information (method, URL, headers, body) +- Response information (status code, headers, body) + +### HTTPS Traffic Files +Filename format: `YYYYMMDD_HHMMSS_domain_direction.bin` + +Contains encrypted binary data. + +## Important Notes + +1. **Administrator Privileges**: Program needs administrator privileges to modify system proxy settings and install certificates +2. **Certificate Security**: Please ensure the security of P12 certificate files, do not hardcode passwords in production environments +3. **Network Security**: This tool is only for legal network debugging and testing purposes +4. **System Compatibility**: Currently only supports Windows systems + +## Troubleshooting + +1. **Certificate Loading Failed**: + - Check P12 file path and password + - Ensure OpenSSL is installed (optional) + +2. **Proxy Setting Failed**: + - Ensure running with administrator privileges + - Check if port 8080 is occupied + +3. **CA Certificate Installation Failed**: + - Ensure CA.crt file exists and format is correct + - Check administrator privileges + +## Development and Customization + +You can modify the following parts as needed: +- Add more domains of interest in `config.toml` +- Modify proxy port +- Customize traffic dump format +- Add more traffic analysis features + +## License + +Please see the LICENSE file for license information. \ No newline at end of file diff --git a/TROUBLESHOOTING.md b/TROUBLESHOOTING.md new file mode 100644 index 0000000..8ce42db --- /dev/null +++ b/TROUBLESHOOTING.md @@ -0,0 +1,151 @@ +# MITM Proxy Troubleshooting Guide + +## ERR_TUNNEL_CONNECTION_FAILED Error + +This error typically occurs when the browser cannot establish a secure tunnel through the proxy. Here are the most common causes and solutions: + +### 1. Certificate Issues + +**Problem**: The CA certificate is not properly installed or trusted by the browser. + +**Solutions**: +- Run the program as Administrator to ensure certificate installation +- Manually verify certificate installation: + ```cmd + certlm.msc + ``` + Check if "Charles Proxy CA" appears in "Trusted Root Certification Authorities" + +- If certificate installation fails, try: + ```cmd + certutil -addstore -f "Root" CA.crt + ``` + +### 2. Proxy Configuration Issues + +**Problem**: System proxy is not properly configured or there are conflicting proxy settings. + +**Solutions**: +- Verify proxy settings in Windows: + - Go to Settings > Network & Internet > Proxy + - Ensure "Use a proxy server" is enabled + - Check that proxy address is `127.0.0.1:8080` + +- Clear existing proxy settings: + ```cmd + netsh winhttp reset proxy + ``` + +### 3. Firewall/Antivirus Blocking + +**Problem**: Security software is blocking the proxy connections. + +**Solutions**: +- Temporarily disable Windows Firewall +- Add exception for the proxy program in antivirus software +- Add exception for port 8080 + +### 4. TLS Handshake Issues + +**Problem**: The proxy cannot properly negotiate TLS connections. + +**Solutions**: +- The updated code now includes: + - Better TLS handshake handling + - Fallback to transparent proxy mode + - Improved error logging + - Connection timeouts + +### 5. Testing and Debugging + +Use the built-in test mode to verify connectivity: + +```cmd +# Run with test flag +go run . -test +``` + +This will: +- Start the proxy server +- Test HTTP and HTTPS connections +- Show detailed error messages +- Help identify the specific issue + +### 6. Common Error Messages and Solutions + +**"TLS handshake failed"**: +- Certificate not trusted by browser +- Try accessing a simple HTTP site first +- Check certificate installation + +**"Failed to connect to target server"**: +- Network connectivity issue +- DNS resolution problems +- Target server blocking connections + +**"Write error" or "Read error"**: +- Connection interrupted +- Network timeout +- Proxy overloaded + +**HTTP Redirects (302/301) Issues**: +- ✅ FIXED: Proxy is now completely transparent +- All redirects are passed through exactly as-is +- Browser handles redirects automatically +- No interference with redirect chains + +### 7. Manual Testing Steps + +1. **Test without proxy**: + ```cmd + curl https://httpbin.org/ip + ``` + +2. **Test with proxy**: + ```cmd + curl --proxy 127.0.0.1:8080 https://httpbin.org/ip + ``` + +3. **Test certificate**: + ```cmd + curl --proxy 127.0.0.1:8080 --insecure https://httpbin.org/ip + ``` + +### 8. Browser-Specific Issues + +**Chrome**: +- Clear SSL state: Settings > Privacy and security > Security > Manage certificates > Clear SSL state +- Disable certificate transparency checks temporarily + +**Firefox**: +- Import certificate manually: Settings > Privacy & Security > Certificates > Import +- Disable OCSP checking temporarily + +**Edge**: +- Same as Chrome (uses Windows certificate store) + +### 9. Advanced Debugging + +Enable verbose logging by modifying the code to show more details: +- Connection attempts +- TLS handshake details +- Certificate validation steps +- Network I/O operations + +### 10. Alternative Solutions + +If the proxy still doesn't work: + +1. **Use transparent mode only**: Modify code to skip TLS termination +2. **Use different certificate**: Generate new certificates with proper SAN fields +3. **Use different port**: Change from 8080 to 8081 or 3128 +4. **Bypass problematic domains**: Add exceptions for specific sites + +## Getting Help + +If none of these solutions work: + +1. Run with `-test` flag and save the output +2. Check Windows Event Viewer for errors +3. Use Process Monitor to see file/registry access issues +4. Provide the exact error message and browser version diff --git a/UTF8_FIX_README.md b/UTF8_FIX_README.md new file mode 100644 index 0000000..bf0b7ef --- /dev/null +++ b/UTF8_FIX_README.md @@ -0,0 +1,75 @@ +# UTF-8 Encoding Fix for Chinese Windows Systems + +## Problem +On Chinese Windows systems, the default console encoding is often GBK/GB2312, which causes garbled text when the MITM proxy outputs UTF-8 characters. This results in unreadable console output, especially for Unicode characters and symbols. + +## Solution +This fix implements a comprehensive UTF-8 encoding solution for Windows systems: + +### 1. Batch File Fixes +All batch files now include the command: +```batch +chcp 65001 >nul 2>&1 +``` +This sets the console code page to UTF-8 (65001) before running any commands. + +**Fixed files:** +- `run.bat` +- `demo.bat` +- `build.bat` +- `test.bat` + +### 2. Go Program Fixes +The main Go program now automatically sets the console to UTF-8 mode on Windows: + +```go +// Set console to UTF-8 on Windows to prevent garbled text +if runtime.GOOS == "windows" { + setConsoleUTF8() +} +``` + +**Implementation details:** +- Added `setConsoleUTF8()` function that executes `chcp 65001` +- Automatic detection of Windows OS using `runtime.GOOS` +- Enhanced console output with UTF-8 symbols (✓, 🚀, 🛑, etc.) + +### 3. Testing +A test script `utf8_test.bat` is provided to verify the fix works correctly: +```batch +utf8_test.bat +``` + +This script: +- Sets console to UTF-8 +- Displays various Unicode characters (Chinese, Japanese, Korean) +- Runs the MITM proxy in test mode to verify UTF-8 output + +## Usage +Simply run any of the batch files as usual. The UTF-8 encoding will be automatically configured: + +```batch +run.bat # Start the proxy with UTF-8 support +demo.bat # Run the demo with UTF-8 support +utf8_test.bat # Test UTF-8 encoding specifically +``` + +## Verification +After applying the fix, you should see: +- ✓ Clear display of Unicode characters +- 🚀 Proper rendering of emoji symbols +- 正确显示中文字符 (Correct display of Chinese characters) +- 日本語の文字が正しく表示される (Japanese characters display correctly) + +## Technical Notes +- Code page 65001 is the Windows UTF-8 code page +- The fix is automatically applied only on Windows systems +- No changes are needed for Linux/macOS systems +- The original functionality remains unchanged + +## Compatibility +- Windows 10/11: Full support +- Windows 8/8.1: Full support +- Windows 7: Partial support (depends on system configuration) +- Chinese, Japanese, Korean Windows: Full support +- English Windows: Full support (no changes to existing behavior) diff --git a/build.bat b/build.bat new file mode 100644 index 0000000..5aebee2 --- /dev/null +++ b/build.bat @@ -0,0 +1,29 @@ +@echo off +REM Set console to UTF-8 encoding to prevent garbled text on Chinese Windows systems +chcp 65001 >nul 2>&1 +echo Building MITM Proxy Server... + +REM Download dependencies +echo Downloading dependencies... +go mod download + +REM Build program +echo Building executable... +go build -o mitm.exe . + +if %ERRORLEVEL% EQU 0 ( + echo. + echo Build successful! + echo Executable: mitm.exe + echo. + echo Usage: + echo 1. Ensure cert.p12 and CA.crt files exist + echo 2. Edit config.toml configuration file + echo 3. Run mitm.exe as administrator + echo. +) else ( + echo. + echo Build failed! Please check error messages. +) + +pause \ No newline at end of file diff --git a/cert.p12 b/cert.p12 new file mode 100644 index 0000000..4e16e63 Binary files /dev/null and b/cert.p12 differ diff --git a/cert_base64.txt b/cert_base64.txt new file mode 100644 index 0000000..e90a3ef --- /dev/null +++ b/cert_base64.txt @@ -0,0 +1,69 @@ +-----BEGIN CERTIFICATE----- +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 +BBTOPefdAsbPZURS9djPzGhmw0NCbQICJxA= +-----END CERTIFICATE----- diff --git a/cert_utils.go b/cert_utils.go new file mode 100644 index 0000000..d3d8f97 --- /dev/null +++ b/cert_utils.go @@ -0,0 +1,268 @@ +package main + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" + "encoding/base64" + "encoding/pem" + "fmt" + "math/big" + "net" + "strings" + "time" + + "software.sslmate.com/src/go-pkcs12" +) + +// Hardcoded certificate data - users need to replace these placeholders with actual certificate data +const ( + // Base64 encoded data of P12 certificate - users need to replace with actual cert.p12 file content + hardcodedP12Data = `-----BEGIN CERTIFICATE----- +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 +BBTOPefdAsbPZURS9djPzGhmw0NCbQICJxA= +-----END CERTIFICATE-----` + + // PEM format data of CA certificate - users need to replace with actual CA.crt file content + hardcodedCACert = `-----BEGIN CERTIFICATE----- +MIIFOTCCBCGgAwIBAgIGAZi8TmIsMA0GCSqGSIb3DQEBCwUAMIGgMTEwLwYDVQQDDChDaGFybGVz +IFByb3h5IENBICgxOCBBdWcgMjAyNSwgQkxBQ0stUEMpMSUwIwYDVQQLDBxodHRwczovL2NoYXJs +ZXNwcm94eS5jb20vc3NsMREwDwYDVQQKDAhYSzcyIEx0ZDERMA8GA1UEBwwIQXVja2xhbmQxETAP +BgNVBAgMCEF1Y2tsYW5kMQswCQYDVQQGEwJOWjAeFw0yNTA4MTcwODMxNTBaFw0yNjA4MTcwODMx +NTBaMIGgMTEwLwYDVQQDDChDaGFybGVzIFByb3h5IENBICgxOCBBdWcgMjAyNSwgQkxBQ0stUEMp +MSUwIwYDVQQLDBxodHRwczovL2NoYXJsZXNwcm94eS5jb20vc3NsMREwDwYDVQQKDAhYSzcyIEx0 +ZDERMA8GA1UEBwwIQXVja2xhbmQxETAPBgNVBAgMCEF1Y2tsYW5kMQswCQYDVQQGEwJOWjCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKEmwh2Lk0017ak2c+3eKUGRsZVc5TSfcFaaiAk5 +kKMWj0pIXNKo2G8eERo4BYNqZi+icHGWBwmhAuUDJqpZMji2Qzv0jvuFDw0+UVVtp30RU/92GZYV +C44df+qPTYqUuD+ZPKdlo2RZ38Jbru/VT7AQQ53cvcBJ6s7WzY9QQVui1Rd3jHRXnyb9/duccw22 +vo6f2/OX2mVEKpXd5/3g8d+D8EuoiTUKDbgM39diOYuelh8Xybf0Zy1ZU4nkYeaVwzf9djlgxa1E +2Qb9SscxddGBJxyTrqtoG4ZLwzuwz3DX6KOEPX73I0Q8L+TBf7KQhBYkHSOa6HygE0Vgi3HoM4UC +AwEAAaOCAXUwggFxMA8GA1UdEwEB/wQFMAMBAf8wggEtBglghkgBhvhCAQ0EggEeE4IBGlRoaXMg +cm9vdCBjZXJ0aWZpY2F0ZSB3YXMgZ2VuZXJhdGVkIGJ5IENoYXJsZXMgUHJveHkgZm9yIFNTTCBQ +cm94eWluZy4gSWYgdGhpcyBjZXJ0aWZpY2F0ZSBpcyBwYXJ0IG9mIGEgY2VydGlmaWNhdGUgY2hh +aW4sIHRoaXMgbWVhbnMgdGhhdCB5b3UncmUgYnJvd3NpbmcgdGhyb3VnaCBDaGFybGVzIFByb3h5 +IHdpdGggU1NMIFByb3h5aW5nIGVuYWJsZWQgZm9yIHRoaXMgd2Vic2l0ZS4gUGxlYXNlIHNlZSBo +dHRwczovL2NoYXJsZXNwcm94eS5jb20vc3NsIGZvciBtb3JlIGluZm9ybWF0aW9uLjAOBgNVHQ8B +Af8EBAMCAgQwHQYDVR0OBBYEFKBf+QLehq0dc4s7YMIUUFJdgWBfMA0GCSqGSIb3DQEBCwUAA4IB +AQBc+K3gGnz00yv2XMYRMbeYLr3SD15Tx3NAPri08EY1wyyufkBCaI81tZSCMy4PkGAYN+zODrQ6 +MRj0tbABTNZHdzFCuazE+B2ce2Ka3PcQ1DNpGf60NYk9qBHpOxak+5XxrECFYjStYW3gLZ7mZSnI +YX9doSujRpzSbVZFvVh4J1zCzF1NuD6VxxfFjppJ6EnvnSSQOly0e32NzibQi3akFb4E5hn58py/ +Eth3xl7mzWjcdKeKd30TAeg98PA+drJ8JsunIc2sICcNuAoVSKQEX4ihZHMhFLXl0MNdyWQtqHPR +beQU9SvWF3DVmilrNO1neetL2TCZK5iMyIAHvqPo +-----END CERTIFICATE-----` + + // P12 certificate password - users need to modify to actual password + hardcodedP12Password = "Admin!23" +) + +// loadHardcodedCertificate loads hardcoded P12 certificate +func loadHardcodedCertificate() (*tls.Config, error) { + // If hardcoded data is empty or placeholder, generate self-signed certificate + if len(hardcodedP12Data) < 100 { + fmt.Println("Warning: No valid P12 certificate data provided, generating self-signed certificate for testing") + return generateSelfSignedCert() + } + + // Decode base64 data + p12Data, err := decodeBase64String(hardcodedP12Data) + if err != nil { + fmt.Printf("Warning: Unable to decode P12 data (%v), generating self-signed certificate\n", err) + return generateSelfSignedCert() + } + + // Parse P12 data + privateKey, cert, caCerts, err := pkcs12.DecodeChain(p12Data, hardcodedP12Password) + if err != nil { + fmt.Printf("Warning: Unable to parse P12 certificate (%v), generating self-signed certificate\n", err) + return generateSelfSignedCert() + } + + // Create certificate chain + certificates := []tls.Certificate{ + { + Certificate: [][]byte{cert.Raw}, + PrivateKey: privateKey, + }, + } + + // Create CA certificate pool + caCertPool := x509.NewCertPool() + for _, caCert := range caCerts { + caCertPool.AddCert(caCert) + } + + // If there's a hardcoded CA certificate, add it to the pool + if len(hardcodedCACert) > 100 { + block, _ := pem.Decode([]byte(hardcodedCACert)) + if block != nil { + if caCert, err := x509.ParseCertificate(block.Bytes); err == nil { + caCertPool.AddCert(caCert) + } + } + } + + return &tls.Config{ + Certificates: certificates, + RootCAs: caCertPool, + InsecureSkipVerify: true, + }, nil +} + +// decodeBase64String decodes base64 string, ignoring whitespace and comments +func decodeBase64String(data string) ([]byte, error) { + // Remove comment lines and whitespace + var cleanData strings.Builder + lines := strings.SplitSeq(data, "\n") + for line := range lines { + line = strings.TrimSpace(line) + if len(line) > 0 && !strings.HasPrefix(line, "--") { + cleanData.WriteString(line) + } + } + + if cleanData.Len() == 0 { + return nil, fmt.Errorf("no valid base64 data") + } + + // Use standard base64 decoding + return base64.StdEncoding.DecodeString(cleanData.String()) +} + +// generateSelfSignedCert generates self-signed certificate for testing +func generateSelfSignedCert() (*tls.Config, error) { + // Generate private key + privateKey, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + return nil, err + } + + // Create certificate template + template := x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{ + Organization: []string{"MITM Proxy"}, + OrganizationalUnit: []string{"MITM Proxy CA"}, + Country: []string{"US"}, + Province: []string{""}, + Locality: []string{""}, + StreetAddress: []string{""}, + PostalCode: []string{""}, + CommonName: "MITM Proxy Root CA", + }, + NotBefore: time.Now(), + NotAfter: time.Now().Add(365 * 24 * time.Hour), + // Proper key usage for CA certificate + KeyUsage: x509.KeyUsageKeyEncipherment | + x509.KeyUsageDigitalSignature | + x509.KeyUsageCertSign | + x509.KeyUsageCRLSign, + // Extended key usage for server authentication + ExtKeyUsage: []x509.ExtKeyUsage{ + x509.ExtKeyUsageServerAuth, + x509.ExtKeyUsageClientAuth, + }, + BasicConstraintsValid: true, + IsCA: true, + MaxPathLen: 0, + MaxPathLenZero: true, + // Add Subject Alternative Names for flexibility + DNSNames: []string{ + "localhost", + "*.localhost", + "127.0.0.1", + }, + IPAddresses: []net.IP{ + net.IPv4(127, 0, 0, 1), + net.IPv6loopback, + }, + } + + // Generate certificate + certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &privateKey.PublicKey, privateKey) + if err != nil { + return nil, err + } + + // Create TLS certificate + cert := tls.Certificate{ + Certificate: [][]byte{certDER}, + PrivateKey: privateKey, + } + + return &tls.Config{ + Certificates: []tls.Certificate{cert}, + InsecureSkipVerify: true, + }, nil +} + +// getHardcodedCACert returns hardcoded CA certificate +func getHardcodedCACert() string { + return hardcodedCACert +} diff --git a/certificate_guide.md b/certificate_guide.md new file mode 100644 index 0000000..6f17ca9 --- /dev/null +++ b/certificate_guide.md @@ -0,0 +1,124 @@ +# Certificate Configuration Guide + +## 📋 Overview + +This program now uses hardcoded certificate data and does not require external certificate files. You need to embed the certificate data into the source code. + +## 🔧 Configuration Steps + +### Step 1: Prepare Certificate Files + +Ensure you have the following files: +- `cert.p12` - PKCS#12 format certificate file (contains private key and certificate) +- `CA.crt` - CA root certificate file + +### Step 2: Convert P12 Certificate to Base64 + +#### Windows System: +```cmd +certutil -encode cert.p12 cert_base64.txt +``` + +#### Linux/Mac System: +```bash +base64 cert.p12 > cert_base64.txt +``` + +### Step 3: Edit Source Code + +Open the `cert_utils.go` file and find the following constants to replace: + +#### 1. P12 Certificate Data +Copy the content of `cert_base64.txt` to the `hardcodedP12Data` constant: + +```go +const ( + hardcodedP12Data = ` +MIIKYwIBAzCCCh8GCSqGSIb3DQEHAaCCChAEggmMIIIJiDCCBW8GCSqGSIb3DQEH +BqCCBWAwggVcAgEAMIIFVQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQI7n7Q +... (your base64 certificate data) +` +``` + +#### 2. CA Certificate Data +Copy the complete PEM content of the `CA.crt` file to the `hardcodedCACert` constant: + +```go +hardcodedCACert = `-----BEGIN CERTIFICATE----- +MIIDXTCCAkWgAwIBAgIJAKoK/OvD/h8wMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +... (your CA certificate data) +-----END CERTIFICATE-----` +``` + +#### 3. Certificate Password +Modify the certificate password: + +```go +hardcodedP12Password = "your_actual_password" +``` + +### Step 4: Recompile + +After configuration is complete, recompile the program: + +```bash +go build -o mitm.exe . +``` + +## ✅ Verify Configuration + +When starting the program, you should see: +- ✅ "CA certificate installed successfully" - indicates CA certificate is configured correctly +- ✅ No certificate-related error messages + +If you see "Warning: No valid P12 certificate data provided, generating self-signed certificate for testing", it means the P12 certificate configuration has issues. + +## 🔍 Feature Improvements + +### HTTPS Traffic Decryption +The program can now: +1. **Transparent Proxy** - When TLS decryption fails, still proxy encrypted traffic +2. **Decryption Proxy** - Use your certificate to decrypt HTTPS traffic +3. **Dual Dump** - Save both encrypted and decrypted data + +### Output File Format +- `timestamp_domain_request_encrypted.bin` - Encrypted request data +- `timestamp_domain_request_decrypted.bin` - Decrypted request data +- `timestamp_domain_response_encrypted.bin` - Encrypted response data +- `timestamp_domain_response_decrypted.bin` - Decrypted response data + +### Complete Data Output +Console output now shows: +- Complete HTTP request/response data (no longer truncated) +- Complete HTTPS decrypted traffic content +- Data length information + +## ⚠️ Security Considerations + +1. **Source Code Security** - Certificate data is now embedded in source code, ensure source code security +2. **Password Protection** - Consider using environment variables or other methods to protect certificate passwords +3. **Certificate Validity** - Regularly check and update embedded certificates +4. **Access Control** - Restrict access to compiled programs + +## 🐛 Troubleshooting + +### Issue 1: Certificate Parsing Failed +**Cause**: Base64 data format error or incomplete +**Solution**: Check base64 conversion process, ensure data integrity + +### Issue 2: TLS Handshake Failed +**Cause**: Certificate doesn't match domain or certificate has expired +**Solution**: Check certificate validity and domain configuration + +### Issue 3: CA Certificate Installation Failed +**Cause**: CA certificate format error or insufficient permissions +**Solution**: Ensure running with administrator privileges, check CA certificate format + +## 📞 Technical Support + +If you encounter configuration issues: +1. Check certificate file format and validity +2. Verify base64 conversion results +3. Confirm running with administrator privileges +4. Check console error messages diff --git a/config.go b/config.go new file mode 100644 index 0000000..632bc52 --- /dev/null +++ b/config.go @@ -0,0 +1,101 @@ +package main + +import ( + "bufio" + "fmt" + "os" + "strconv" + "strings" +) + +// Simple TOML parser, only handles basic formats we need +func parseConfig(filename string) (*Config, error) { + file, err := os.Open(filename) + if err != nil { + return nil, err + } + defer file.Close() + + config := &Config{ + DomainsOfInterest: []string{}, + } + + // Set default values + config.Proxy.Port = 8080 + config.Dump.OutputDir = "traffic_dumps" + + scanner := bufio.NewScanner(file) + var currentSection string + + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) + + // Skip empty lines and comments + if line == "" || strings.HasPrefix(line, "#") { + continue + } + + // Check if it's a section title + if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") { + currentSection = strings.Trim(line, "[]") + continue + } + + // Parse key-value pairs + parts := strings.SplitN(line, "=", 2) + if len(parts) != 2 { + continue + } + + key := strings.TrimSpace(parts[0]) + value := strings.TrimSpace(parts[1]) + + // Handle array values + if strings.HasPrefix(value, "[") && strings.HasSuffix(value, "]") { + arrayStr := strings.Trim(value, "[]") + if key == "domains_of_interest" { + if arrayStr != "" { + items := strings.Split(arrayStr, ",") + for _, item := range items { + item = strings.TrimSpace(item) + item = strings.Trim(item, "\"") + if item != "" { + config.DomainsOfInterest = append(config.DomainsOfInterest, item) + } + } + } + } + continue + } + + // Handle string values + value = strings.Trim(value, "\"") + + // Set values based on current section + switch currentSection { + case "proxy": + switch key { + case "port": + if port, err := strconv.Atoi(value); err == nil { + config.Proxy.Port = port + } + } + case "dump": + switch key { + case "output_dir": + config.Dump.OutputDir = value + } + } + } + + if err := scanner.Err(); err != nil { + return nil, err + } + + return config, nil +} + +func (c *Config) String() string { + return fmt.Sprintf("Config{DomainsOfInterest: %v, Proxy: {Port: %d}, Dump: {OutputDir: %s}}", + c.DomainsOfInterest, c.Proxy.Port, c.Dump.OutputDir) +} diff --git a/config.toml b/config.toml new file mode 100644 index 0000000..95bab7b --- /dev/null +++ b/config.toml @@ -0,0 +1,16 @@ +# Domains of interest configuration +# Requests and responses for these domains will be printed to stdout +domains_of_interest = [ + "example.com", + "httpbin.org", + "api.github.com", + "www.google.com" +] + +# Proxy server configuration +[proxy] +port = 8080 + +# Traffic dump configuration +[dump] +output_dir = "traffic_dumps" diff --git a/debug_proxy.bat b/debug_proxy.bat new file mode 100644 index 0000000..8467bd8 --- /dev/null +++ b/debug_proxy.bat @@ -0,0 +1,60 @@ +@echo off +echo ======================================== +echo MITM Proxy Debug Script +echo ======================================== +echo. +echo This script will help diagnose why HTTPS CONNECT requests +echo are not reaching the proxy server. +echo. +pause + +echo 1. Checking current Windows proxy settings... +reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v ProxyEnable +reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v ProxyServer +reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v ProxyOverride +echo. + +echo 2. Checking WinHTTP proxy settings... +netsh winhttp show proxy +echo. + +echo 3. Testing if proxy port is listening... +netstat -an | findstr ":8080" +echo. + +echo 4. Testing direct connection to proxy... +curl -v --max-time 5 http://127.0.0.1:8080/proxy-health +echo. + +echo 5. Testing HTTP proxy functionality... +curl -v --proxy http://127.0.0.1:8080 --max-time 10 http://httpbin.org/ip +echo. + +echo 6. Testing HTTPS with explicit CONNECT... +echo Sending manual CONNECT request... +( +echo CONNECT httpbin.org:443 HTTP/1.1 +echo Host: httpbin.org:443 +echo. +) | telnet 127.0.0.1 8080 +echo. + +echo 7. Testing HTTPS proxy with curl... +curl -v --proxy http://127.0.0.1:8080 --max-time 15 https://httpbin.org/ip +echo. + +echo 8. Checking for conflicting proxy software... +tasklist | findstr /i "fiddler\|charles\|burp\|owasp" +echo. + +echo 9. Testing with different curl proxy syntax... +curl -v -x 127.0.0.1:8080 --max-time 15 https://httpbin.org/ip +echo. + +echo Debug complete. +echo. +echo IMPORTANT: Check the MITM proxy console output during these tests. +echo If you see NO CONNECT requests in the proxy logs, the issue is +echo with Windows proxy configuration or browser proxy detection. +echo. +pause diff --git a/demo.bat b/demo.bat new file mode 100644 index 0000000..d68fc7b --- /dev/null +++ b/demo.bat @@ -0,0 +1,100 @@ +@echo off +REM Set console to UTF-8 encoding to prevent garbled text on Chinese Windows systems +chcp 65001 >nul 2>&1 + +echo ======================================== +echo MITM Proxy Server Functionality Demo +echo ======================================== +echo. + +REM Check for Administrator privileges +net session >nul 2>&1 +if %errorLevel% neq 0 ( + echo Error: Administrator privileges required! + echo Please right-click this script and select "Run as administrator" + pause + exit /b 1 +) + +echo ✅ Administrator privileges check passed + +REM Check program file +if not exist "mitm.exe" ( + echo ❌ mitm.exe not found, compiling... + go build -o mitm.exe . + if %errorLevel% neq 0 ( + echo ❌ Compilation failed! + pause + exit /b 1 + ) + echo ✅ Compilation successful +) else ( + echo ✅ Program file exists +) + +REM Check configuration file +if not exist "config.toml" ( + echo ❌ config.toml not found! + pause + exit /b 1 +) +echo ✅ Configuration file exists + +REM Create output directory +if not exist "traffic_dumps" mkdir traffic_dumps +echo ✅ Output directory created + +echo. +echo ======================================== +echo Function Description +echo ======================================== +echo 📡 HTTP/HTTPS Proxy: 127.0.0.1:8080 +echo 📁 Traffic Dump Directory: traffic_dumps/ +echo 🔍 Domains of Interest: Configure in config.toml +echo 🔐 HTTPS Decryption: Uses hardcoded certificates (if configured) +echo 📄 Full Data Output: Displayed without truncation +echo. + +echo ======================================== +echo Test Suggestions +echo ======================================== +echo 1. After starting the program, visit: http://httpbin.org/get +echo 2. Visit: https://httpbin.org/get (Test HTTPS) +echo 3. Check files in traffic_dumps/ directory +echo 4. Observe the complete data output in the console +echo. + +echo ======================================== +echo Certificate Configuration Status +echo ======================================== +findstr /C:"将您的cert.p12文件转换为base64字符串并粘贴在这里" cert_utils.go >nul +if %errorLevel% equ 0 ( + echo ⚠️ P12 Certificate: Not configured (using self-signed certificate) + echo Please refer to certificate_guide.md to configure a real certificate +) else ( + echo ✅ P12 Certificate: Configured +) + +findstr /C:"将您的CA.crt文件内容粘贴在这里" cert_utils.go >nul +if %errorLevel% equ 0 ( + echo ⚠️ CA Certificate: Not configured +) else ( + echo ✅ CA Certificate: Configured +) + +echo. +echo ======================================== +echo Start Program +echo ======================================== +echo Program will start in 5 seconds... +echo Press Ctrl+C to stop the program +echo. +timeout /t 5 /nobreak >nul + +echo Starting MITM proxy server... +echo. +mitm.exe + +echo. +echo Program exited. +pause \ No newline at end of file diff --git a/diagnose_proxy.bat b/diagnose_proxy.bat new file mode 100644 index 0000000..2701ade --- /dev/null +++ b/diagnose_proxy.bat @@ -0,0 +1,34 @@ +@echo off +echo ======================================== +echo MITM Proxy Diagnostic Tool +echo ======================================== +echo. + +echo 1. Testing if port 8080 is listening... +netstat -an | findstr ":8080" +if %errorlevel% neq 0 ( + echo ❌ Port 8080 is not listening +) else ( + echo ✅ Port 8080 is listening +) +echo. + +echo 2. Testing direct HTTP connection to proxy... +curl -v --max-time 5 http://127.0.0.1:8080/proxy-health 2>&1 +echo. + +echo 3. Checking Windows proxy settings... +reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v ProxyEnable +reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v ProxyServer +echo. + +echo 4. Testing proxy with simple HTTP request... +curl -v --proxy http://127.0.0.1:8080 --max-time 10 http://httpbin.org/ip 2>&1 +echo. + +echo 5. Checking if any process is using port 8080... +netstat -ano | findstr ":8080" +echo. + +echo Diagnostic complete. +pause diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..5ec5887 --- /dev/null +++ b/go.mod @@ -0,0 +1,10 @@ +module mitm + +go 1.25 + +require ( + golang.org/x/sys v0.15.0 + software.sslmate.com/src/go-pkcs12 v0.4.0 +) + +require golang.org/x/crypto v0.17.0 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..caca033 --- /dev/null +++ b/go.sum @@ -0,0 +1,6 @@ +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k= +software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= diff --git a/main.go b/main.go new file mode 100644 index 0000000..30df443 --- /dev/null +++ b/main.go @@ -0,0 +1,1144 @@ +package main + +import ( + "bytes" + "context" + "crypto/rand" + "crypto/rsa" + "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "flag" + "fmt" + "io" + "log" + "math/big" + "net" + "net/http" + "net/url" + "os" + "os/exec" + "os/signal" + "path/filepath" + "runtime" + "strings" + "syscall" + "time" + + "golang.org/x/sys/windows/registry" +) + +type Config struct { + DomainsOfInterest []string + Proxy struct { + Port int + } + Dump struct { + OutputDir string + } +} + +type ProxyServer struct { + config *Config + tlsConfig *tls.Config + server *http.Server + originalProxy string +} + +// testMode can be set via build flags for UTF-8 testing +var testMode string + +func main() { + // Parse command line flags + var testConnectivity = flag.Bool("test", false, "Test proxy connectivity") + flag.Parse() + + // Set console to UTF-8 on Windows to prevent garbled text + if runtime.GOOS == "windows" { + setConsoleUTF8() + } + + fmt.Println("Starting MITM proxy server...") + + // If in test mode, output UTF-8 test characters and exit + if testMode == "true" { + fmt.Println("========================================") + fmt.Println("UTF-8 Encoding Test") + fmt.Println("========================================") + fmt.Println("Testing Unicode characters:") + fmt.Println("English: Hello World") + fmt.Println("Chinese: 你好世界") + fmt.Println("Japanese: こんにちは世界") + fmt.Println("Korean: 안녕하세요 세계") + fmt.Println("Symbols: ✓ ✗ ★ ♥ ◆ ▲") + fmt.Println("") + fmt.Println("If you can see the above characters correctly,") + fmt.Println("UTF-8 encoding is working properly in the MITM proxy.") + fmt.Println("========================================") + return + } + + // Load configuration + config, err := loadConfig("config.toml") + if err != nil { + log.Fatalf("Failed to load configuration: %v", err) + } + + // Create output directory + if err := os.MkdirAll(config.Dump.OutputDir, 0755); err != nil { + log.Fatalf("Failed to create output directory: %v", err) + } + + // Create proxy server + proxy, err := NewProxyServer(config) + if err != nil { + log.Fatalf("Failed to create proxy server: %v", err) + } + + // Install CA certificate + if err := proxy.installCACert(); err != nil { + log.Printf("Failed to install CA certificate: %v", err) + } else { + fmt.Println("✓ CA certificate installed successfully") + } + + // Set system proxy + if err := proxy.setSystemProxy(); err != nil { + log.Fatalf("Failed to set system proxy: %v", err) + } + fmt.Printf("✓ System proxy set to 127.0.0.1:%d\n", config.Proxy.Port) + + // Verify proxy settings were applied + if err := proxy.verifyProxySettings(); err != nil { + fmt.Printf("⚠️ Warning: Could not verify proxy settings: %v\n", err) + } else { + fmt.Printf("✓ Proxy settings verified in Windows registry\n") + } + + // Show current proxy configuration for debugging + proxy.showProxyConfiguration() + + // Start proxy server + serverStarted := make(chan error, 1) + go func() { + fmt.Printf("🚀 Starting proxy server on port %d...\n", config.Proxy.Port) + if err := proxy.Start(); err != nil && err != http.ErrServerClosed { + serverStarted <- err + return + } + serverStarted <- nil + }() + + // Wait for server to start or fail + fmt.Printf("⏳ Waiting for server to start...\n") + select { + case err := <-serverStarted: + if err != nil { + log.Fatalf("❌ Failed to start proxy server: %v", err) + } + fmt.Printf("✅ Proxy server successfully started on port %d\n", config.Proxy.Port) + case <-time.After(5 * time.Second): + fmt.Printf("✅ Proxy server appears to be starting (no immediate errors)\n") + } + + // Test basic connectivity first + fmt.Printf("🔍 Testing basic proxy connectivity...\n") + if err := testBasicConnectivity(config.Proxy.Port); err != nil { + fmt.Printf("⚠️ Basic connectivity test failed: %v\n", err) + fmt.Printf("💡 Try running diagnose_proxy.bat for detailed diagnostics\n") + } else { + fmt.Printf("✅ Basic proxy connectivity test passed\n") + } + + // Run full connectivity test if requested + if *testConnectivity { + proxyAddr := fmt.Sprintf("127.0.0.1:%d", config.Proxy.Port) + testProxyConnectivity(proxyAddr) + } + + // Wait for interrupt signal + sigChan := make(chan os.Signal, 1) + signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) + <-sigChan + + fmt.Println("\n🛑 Shutting down proxy server...") + proxy.Shutdown() + fmt.Println("✓ Proxy server closed") +} + +func loadConfig(filename string) (*Config, error) { + return parseConfig(filename) +} + +func NewProxyServer(config *Config) (*ProxyServer, error) { + // Load hardcoded P12 certificate + tlsConfig, err := loadHardcodedCertificate() + if err != nil { + return nil, fmt.Errorf("failed to load certificate: %v", err) + } + + proxy := &ProxyServer{ + config: config, + tlsConfig: tlsConfig, + } + + // Create HTTP server with enhanced logging + // IMPORTANT: Use a custom handler that properly handles CONNECT requests + proxy.server = &http.Server{ + Addr: fmt.Sprintf(":%d", config.Proxy.Port), + Handler: proxy, // Use the proxy itself as the handler + // Add some server configuration for better debugging + ErrorLog: log.New(os.Stdout, "HTTP-SERVER: ", log.LstdFlags), + } + + return proxy, nil +} + +func (p *ProxyServer) Start() error { + fmt.Printf("🔧 Starting HTTP server on %s\n", p.server.Addr) + + // Test if port is available + listener, err := net.Listen("tcp", p.server.Addr) + if err != nil { + return fmt.Errorf("failed to bind to port %s: %v", p.server.Addr, err) + } + + fmt.Printf("✅ Successfully bound to port %s\n", p.server.Addr) + + // Start serving with our listener + return p.server.Serve(listener) +} + +func (p *ProxyServer) Shutdown() { + // Restore system proxy settings + if err := p.restoreSystemProxy(); err != nil { + log.Printf("Failed to restore system proxy: %v", err) + } else { + fmt.Println("✓ System proxy restored") + } + + // Close HTTP server + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + p.server.Shutdown(ctx) +} + +func (p *ProxyServer) createTLSConfigForHost(host string) *tls.Config { + // Create a TLS config that generates certificates on-demand + config := &tls.Config{ + InsecureSkipVerify: true, + GetCertificate: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) { + // Generate a certificate specifically for this host + return p.generateCertificateForHost(info.ServerName) + }, + } + return config +} + +// generateCertificateForHost creates a certificate for a specific hostname +func (p *ProxyServer) generateCertificateForHost(hostname string) (*tls.Certificate, error) { + // Use the CA certificate and key from our base config + if len(p.tlsConfig.Certificates) == 0 { + return nil, fmt.Errorf("no CA certificate available") + } + + caCert := p.tlsConfig.Certificates[0] + + // Parse the CA certificate + caCertParsed, err := x509.ParseCertificate(caCert.Certificate[0]) + if err != nil { + return nil, fmt.Errorf("failed to parse CA certificate: %v", err) + } + + // Generate a new private key for the host certificate + hostPrivateKey, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + return nil, fmt.Errorf("failed to generate host private key: %v", err) + } + + // Create certificate template for the specific host + template := x509.Certificate{ + SerialNumber: big.NewInt(time.Now().UnixNano()), + Subject: pkix.Name{ + Organization: []string{"MITM Proxy"}, + Country: []string{"US"}, + CommonName: hostname, + }, + NotBefore: time.Now(), + NotAfter: time.Now().Add(365 * 24 * time.Hour), + // Proper key usage for server certificate + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{ + x509.ExtKeyUsageServerAuth, + }, + BasicConstraintsValid: true, + IsCA: false, + } + + // Add the hostname to DNS names + template.DNSNames = []string{hostname} + + // If hostname is an IP address, add it to IP addresses + if ip := net.ParseIP(hostname); ip != nil { + template.IPAddresses = []net.IP{ip} + } + + // Generate the certificate signed by our CA + certDER, err := x509.CreateCertificate(rand.Reader, &template, caCertParsed, &hostPrivateKey.PublicKey, caCert.PrivateKey) + if err != nil { + return nil, fmt.Errorf("failed to create certificate for %s: %v", hostname, err) + } + + // Create the TLS certificate + cert := &tls.Certificate{ + Certificate: [][]byte{certDER}, + PrivateKey: hostPrivateKey, + } + + return cert, nil +} + +// ServeHTTP implements http.Handler interface to properly handle all requests including CONNECT +func (p *ProxyServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { + // Handle health check endpoint + if r.URL.Path == "/proxy-health" { + fmt.Printf("🏥 Health check request from %s\n", r.RemoteAddr) + w.Header().Set("Content-Type", "text/plain") + w.WriteHeader(http.StatusOK) + w.Write([]byte("MITM Proxy is running")) + return + } + + // Handle all other requests through our main handler + p.handleHTTP(w, r) +} + +func (p *ProxyServer) handleHTTP(w http.ResponseWriter, r *http.Request) { + // Log all incoming requests for debugging with timestamp + timestamp := time.Now().Format("15:04:05") + fmt.Printf("[%s] 📥 INCOMING: %s %s %s from %s\n", timestamp, r.Method, r.Host, r.URL.Path, r.RemoteAddr) + fmt.Printf("[%s] 📋 Headers: %d headers received\n", timestamp, len(r.Header)) + + // Log ALL headers for debugging proxy issues + for name, values := range r.Header { + for _, value := range values { + fmt.Printf("[%s] 📋 Header: %s: %s\n", timestamp, name, value) + } + } + + // Log the complete URL being requested + fmt.Printf("[%s] 🌐 Full URL: %s\n", timestamp, r.URL.String()) + + // Check if this is actually an HTTPS request being sent as HTTP + if r.URL.Scheme == "https" { + fmt.Printf("[%s] ⚠️ HTTPS URL received as HTTP request - browser may not be using CONNECT\n", timestamp) + } + + if r.Method == http.MethodConnect { + fmt.Printf("[%s] 🔐 Processing HTTPS CONNECT for %s\n", timestamp, r.Host) + p.handleHTTPS(w, r) + return + } + + // Handle HTTP request + fmt.Printf("[%s] 🌐 Processing HTTP request for %s\n", timestamp, r.Host) + p.handleHTTPRequest(w, r) +} + +func (p *ProxyServer) handleHTTPS(w http.ResponseWriter, r *http.Request) { + timestamp := time.Now().Format("15:04:05") + fmt.Printf("[%s] 🔐 HTTPS CONNECT: Starting for %s from %s\n", timestamp, r.Host, r.RemoteAddr) + + // Get the hijacker before sending any response + hijacker, ok := w.(http.Hijacker) + if !ok { + fmt.Printf("[%s] ❌ HTTPS CONNECT: Hijacking not supported for %s\n", timestamp, r.Host) + http.Error(w, "Hijacking not supported", http.StatusInternalServerError) + return + } + fmt.Printf("[%s] ✅ HTTPS CONNECT: Hijacker obtained for %s\n", timestamp, r.Host) + + // Hijack the connection first + clientConn, _, err := hijacker.Hijack() + if err != nil { + fmt.Printf("[%s] ❌ HTTPS CONNECT: Hijack failed for %s: %v\n", timestamp, r.Host, err) + http.Error(w, err.Error(), http.StatusServiceUnavailable) + return + } + defer func() { + fmt.Printf("[%s] 🔌 HTTPS CONNECT: Closing client connection for %s\n", timestamp, r.Host) + clientConn.Close() + }() + fmt.Printf("[%s] ✅ HTTPS CONNECT: Connection hijacked for %s\n", timestamp, r.Host) + + // Send 200 Connection established response manually + connectResponse := "HTTP/1.1 200 Connection established\r\n\r\n" + written, err := clientConn.Write([]byte(connectResponse)) + if err != nil { + fmt.Printf("[%s] ❌ HTTPS CONNECT: Failed to send response to %s: %v\n", timestamp, r.Host, err) + return + } + fmt.Printf("[%s] ✅ HTTPS CONNECT: Sent %d bytes response to %s\n", timestamp, written, r.Host) + + // Give the client a moment to process the CONNECT response + time.Sleep(100 * time.Millisecond) + + // Try MITM first - if it fails, fall back to transparent proxy + fmt.Printf("[%s] 🔍 HTTPS CONNECT: Attempting MITM for %s\n", timestamp, r.Host) + if !p.attemptMITM(clientConn, r.Host) { + fmt.Printf("[%s] ⚠️ HTTPS CONNECT: MITM failed for %s, falling back to transparent proxy\n", timestamp, r.Host) + p.handleHTTPSTransparent(clientConn, r.Host) + } +} + +// attemptMITM tries to perform MITM decryption, returns true if successful +func (p *ProxyServer) attemptMITM(clientConn net.Conn, host string) bool { + timestamp := time.Now().Format("15:04:05") + fmt.Printf("[%s] 🔍 MITM: Attempting MITM for %s\n", timestamp, host) + + // First establish connection to target server + fmt.Printf("[%s] 🌐 MITM: Connecting to target %s\n", timestamp, host) + destConn, err := tls.Dial("tcp", host, &tls.Config{ + InsecureSkipVerify: true, + }) + if err != nil { + fmt.Printf("[%s] ❌ MITM: Cannot connect to target %s with TLS: %v\n", timestamp, host, err) + return false + } + defer destConn.Close() + fmt.Printf("[%s] ✅ MITM: Connected to target %s\n", timestamp, host) + + // Create TLS config for client connection + fmt.Printf("[%s] 🔧 MITM: Creating TLS config for client connection to %s\n", timestamp, host) + tlsConfig := p.createTLSConfigForHost(host) + + // Wrap client connection with our certificate + fmt.Printf("[%s] 🔐 MITM: Wrapping client connection with our certificate for %s\n", timestamp, host) + tlsClientConn := tls.Server(clientConn, tlsConfig) + defer tlsClientConn.Close() + + // Set handshake timeout + fmt.Printf("[%s] ⏰ MITM: Setting TLS handshake timeout for %s\n", timestamp, host) + tlsClientConn.SetDeadline(time.Now().Add(10 * time.Second)) + + // Try TLS handshake with client + fmt.Printf("[%s] 🤝 MITM: Starting TLS handshake with client for %s\n", timestamp, host) + if err := tlsClientConn.Handshake(); err != nil { + fmt.Printf("[%s] ❌ MITM: TLS handshake failed for %s: %v\n", timestamp, host, err) + return false + } + + // Clear deadline after successful handshake + tlsClientConn.SetDeadline(time.Time{}) + fmt.Printf("[%s] ✅ MITM: TLS handshake successful for %s - decrypting traffic\n", timestamp, host) + + // Create channels for bidirectional copying + done := make(chan struct{}, 2) + + // Copy data bidirectionally with decryption + go func() { + defer func() { + fmt.Printf("[%s] 📤 MITM: Response copying finished for %s\n", timestamp, host) + done <- struct{}{} + }() + p.copyAndDumpDecrypted(destConn, tlsClientConn, host, "response") + }() + + go func() { + defer func() { + fmt.Printf("[%s] 📥 MITM: Request copying finished for %s\n", timestamp, host) + done <- struct{}{} + }() + p.copyAndDumpDecrypted(tlsClientConn, destConn, host, "request") + }() + + // Wait for one direction to close + <-done + fmt.Printf("[%s] 🔚 MITM: Connection to %s closed\n", timestamp, host) + return true +} + +// handleHTTPSTransparent handles transparent HTTPS proxy (when TLS decryption fails) +func (p *ProxyServer) handleHTTPSTransparent(clientConn net.Conn, host string) { + timestamp := time.Now().Format("15:04:05") + fmt.Printf("[%s] 🔄 TRANSPARENT: Starting transparent proxy for %s\n", timestamp, host) + + // Set connection timeout + clientConn.SetDeadline(time.Now().Add(30 * time.Second)) + defer clientConn.SetDeadline(time.Time{}) + + // Establish connection to target server + fmt.Printf("[%s] 🌐 TRANSPARENT: Connecting to target %s\n", timestamp, host) + destConn, err := net.DialTimeout("tcp", host, 10*time.Second) + if err != nil { + fmt.Printf("[%s] ❌ TRANSPARENT: Failed to connect to target server %s: %v\n", timestamp, host, err) + return + } + defer destConn.Close() + fmt.Printf("[%s] ✅ TRANSPARENT: Connected to target %s\n", timestamp, host) + + // Set timeout for destination connection + destConn.SetDeadline(time.Now().Add(30 * time.Second)) + defer destConn.SetDeadline(time.Time{}) + + fmt.Printf("[%s] 🔗 TRANSPARENT: Established transparent proxy connection to %s\n", timestamp, host) + + // Create channels to handle connection closing + done := make(chan struct{}, 2) + + // Transparently proxy encrypted data + go func() { + defer func() { + fmt.Printf("[%s] 📤 TRANSPARENT: Response copying finished for %s\n", timestamp, host) + done <- struct{}{} + }() + p.copyAndDump(destConn, clientConn, host, "response") + }() + + go func() { + defer func() { + fmt.Printf("[%s] 📥 TRANSPARENT: Request copying finished for %s\n", timestamp, host) + done <- struct{}{} + }() + p.copyAndDump(clientConn, destConn, host, "request") + }() + + // Wait for one direction to close, then close both connections + <-done + fmt.Printf("[%s] 🔚 TRANSPARENT: Proxy connection to %s closed\n", timestamp, host) +} + +func (p *ProxyServer) handleHTTPRequest(w http.ResponseWriter, r *http.Request) { + // Build the complete target URL + targetURL := r.URL + if targetURL.Scheme == "" { + targetURL.Scheme = "http" + } + if targetURL.Host == "" { + targetURL.Host = r.Host + } + + // Read request body for dumping + var reqBody []byte + if r.Body != nil { + var err error + reqBody, err = io.ReadAll(r.Body) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + r.Body = io.NopCloser(bytes.NewReader(reqBody)) + } + + // Create new request with exact same properties + proxyReq, err := http.NewRequest(r.Method, targetURL.String(), bytes.NewReader(reqBody)) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Copy ALL headers exactly as-is (completely transparent) + proxyReq.Header = make(http.Header) + for name, values := range r.Header { + proxyReq.Header[name] = values + } + + // Create a completely transparent HTTP client + client := &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, // For MITM purposes + }, + DisableKeepAlives: false, + DisableCompression: true, // Keep original compression + MaxIdleConns: 100, + IdleConnTimeout: 90 * time.Second, + TLSHandshakeTimeout: 10 * time.Second, + ExpectContinueTimeout: 1 * time.Second, + }, + // IMPORTANT: Don't interfere with redirects - let client handle them + CheckRedirect: func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + }, + Timeout: 30 * time.Second, + } + + // Make the request + resp, err := client.Do(proxyReq) + if err != nil { + http.Error(w, err.Error(), http.StatusServiceUnavailable) + return + } + defer resp.Body.Close() + + // Read response body for dumping + respBody, err := io.ReadAll(resp.Body) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Dump traffic for inspection + p.dumpTraffic(r, reqBody, respBody, r.Host) + + // Print traffic if domain is of interest + if p.isDomainOfInterest(r.Host) { + p.printTraffic(r, reqBody, respBody) + } + + // Copy ALL response headers exactly as-is (completely transparent) + for name, values := range resp.Header { + w.Header()[name] = values + } + + // Write the exact response status and body + w.WriteHeader(resp.StatusCode) + w.Write(respBody) +} + +func (p *ProxyServer) copyAndDump(dst io.Writer, src io.Reader, host, direction string) { + buffer := make([]byte, 32768) // Increased buffer size + var allData []byte + totalBytes := 0 + + for { + n, err := src.Read(buffer) + if n > 0 { + data := buffer[:n] + written, writeErr := dst.Write(data) + if writeErr != nil { + fmt.Printf("Write error in %s direction for %s: %v\n", direction, host, writeErr) + break + } + if written != n { + fmt.Printf("Incomplete write in %s direction for %s: wrote %d of %d bytes\n", direction, host, written, n) + } + allData = append(allData, data...) + totalBytes += n + } + if err != nil { + if err != io.EOF { + fmt.Printf("Read error in %s direction for %s: %v\n", direction, host, err) + } + break + } + } + + // Dump encrypted HTTPS traffic + if len(allData) > 0 { + p.dumpHTTPSTraffic(host, direction+"_encrypted", allData) + + // If domain is of interest, print to stdout + if p.isDomainOfInterest(host) { + fmt.Printf("\n=== HTTPS %s Encrypted Traffic: %s ===\n", direction, host) + fmt.Printf("Data length: %d bytes\n", totalBytes) + // Display first 256 bytes of encrypted data (hexadecimal format) + displayLength := len(allData) + if displayLength > 256 { + displayLength = 256 + } + fmt.Printf("Encrypted data content (first %d bytes): %x\n", displayLength, allData[:displayLength]) + fmt.Println("==========================================") + } + } +} + +// copyAndDumpDecrypted copies and dumps decrypted data +func (p *ProxyServer) copyAndDumpDecrypted(dst io.Writer, src io.Reader, host, direction string) { + buffer := make([]byte, 32768) // Increased buffer size + var allData []byte + totalBytes := 0 + + for { + n, err := src.Read(buffer) + if n > 0 { + data := buffer[:n] + written, writeErr := dst.Write(data) + if writeErr != nil { + fmt.Printf("Write error in decrypted %s direction for %s: %v\n", direction, host, writeErr) + break + } + if written != n { + fmt.Printf("Incomplete write in decrypted %s direction for %s: wrote %d of %d bytes\n", direction, host, written, n) + } + allData = append(allData, data...) + totalBytes += n + } + if err != nil { + if err != io.EOF { + fmt.Printf("Read error in decrypted %s direction for %s: %v\n", direction, host, err) + } + break + } + } + + // Dump decrypted HTTPS traffic + if len(allData) > 0 { + p.dumpHTTPSTraffic(host, direction+"_decrypted", allData) + + // If domain is of interest, print to stdout + if p.isDomainOfInterest(host) { + fmt.Printf("\n=== HTTPS %s Decrypted Traffic: %s ===\n", direction, host) + fmt.Printf("Data length: %d bytes\n", totalBytes) + // Display complete decrypted data (limit to first 2KB for readability) + displayLength := len(allData) + if displayLength > 2048 { + displayLength = 2048 + } + fmt.Printf("Decrypted data content (first %d bytes): %s\n", displayLength, string(allData[:displayLength])) + fmt.Println("==========================================") + } + } +} + +func (p *ProxyServer) dumpTraffic(req *http.Request, reqBody, respBody []byte, host string) { + timestamp := time.Now().Format("20060102_150405") + filename := fmt.Sprintf("%s_%s.txt", timestamp, sanitizeFilename(host)) + filepath := filepath.Join(p.config.Dump.OutputDir, filename) + + file, err := os.Create(filepath) + if err != nil { + log.Printf("Failed to create dump file: %v", err) + return + } + defer file.Close() + + // Write request information + fmt.Fprintf(file, "=== REQUEST ===\n") + fmt.Fprintf(file, "%s %s %s\n", req.Method, req.URL.String(), req.Proto) + fmt.Fprintf(file, "Host: %s\n", req.Host) + for name, values := range req.Header { + for _, value := range values { + fmt.Fprintf(file, "%s: %s\n", name, value) + } + } + fmt.Fprintf(file, "\n") + + // Write request body + if len(reqBody) > 0 { + fmt.Fprintf(file, "%s\n", string(reqBody)) + } + + // Write response information + fmt.Fprintf(file, "\n=== RESPONSE ===\n") + fmt.Fprintf(file, "%s\n", string(respBody)) +} + +func (p *ProxyServer) dumpHTTPSTraffic(host, direction string, data []byte) { + timestamp := time.Now().Format("20060102_150405") + filename := fmt.Sprintf("%s_%s_%s.bin", timestamp, sanitizeFilename(host), direction) + filepath := filepath.Join(p.config.Dump.OutputDir, filename) + + file, err := os.Create(filepath) + if err != nil { + log.Printf("Failed to create HTTPS dump file: %v", err) + return + } + defer file.Close() + + file.Write(data) +} + +func (p *ProxyServer) isDomainOfInterest(host string) bool { + // Remove port number + if colonIndex := strings.Index(host, ":"); colonIndex != -1 { + host = host[:colonIndex] + } + + for _, domain := range p.config.DomainsOfInterest { + if strings.Contains(host, domain) { + return true + } + } + return false +} + +func (p *ProxyServer) printTraffic(req *http.Request, reqBody, respBody []byte) { + fmt.Printf("\n=== Traffic from Domain of Interest: %s ===\n", req.Host) + fmt.Printf("Request: %s %s\n", req.Method, req.URL.String()) + + // Print request headers + fmt.Println("Request Headers:") + for name, values := range req.Header { + for _, value := range values { + fmt.Printf(" %s: %s\n", name, value) + } + } + + // Print complete request body + if len(reqBody) > 0 { + fmt.Printf("Request Body (%d bytes): %s\n", len(reqBody), string(reqBody)) + } + + // Print complete response body + if len(respBody) > 0 { + fmt.Printf("Response Body (%d bytes): %s\n", len(respBody), string(respBody)) + } + fmt.Println("==========================================") +} + +func sanitizeFilename(filename string) string { + // Replace unsafe characters + replacer := strings.NewReplacer( + ":", "_", + "/", "_", + "\\", "_", + "*", "_", + "?", "_", + "\"", "_", + "<", "_", + ">", "_", + "|", "_", + ) + return replacer.Replace(filename) +} + +func (p *ProxyServer) setSystemProxy() error { + // Get current proxy settings + k, err := registry.OpenKey(registry.CURRENT_USER, `Software\Microsoft\Windows\CurrentVersion\Internet Settings`, registry.QUERY_VALUE) + if err != nil { + return err + } + defer k.Close() + + // Read current ProxyServer settings + currentProxy, _, err := k.GetStringValue("ProxyServer") + if err == nil { + p.originalProxy = currentProxy + } + + // Set new proxy + k, err = registry.OpenKey(registry.CURRENT_USER, `Software\Microsoft\Windows\CurrentVersion\Internet Settings`, registry.SET_VALUE) + if err != nil { + return err + } + defer k.Close() + + proxyAddr := fmt.Sprintf("127.0.0.1:%d", p.config.Proxy.Port) + + // Enable proxy + if err := k.SetDWordValue("ProxyEnable", 1); err != nil { + return err + } + + // Set proxy server address for BOTH HTTP and HTTPS + // Format: "http=proxy:port;https=proxy:port" or just "proxy:port" for both + if err := k.SetStringValue("ProxyServer", proxyAddr); err != nil { + return err + } + + // Ensure no proxy bypass for local addresses + if err := k.SetStringValue("ProxyOverride", ""); err != nil { + // This is not critical, continue anyway + fmt.Printf("Warning: Could not set ProxyOverride: %v\n", err) + } + + // Refresh IE settings and notify system + return p.refreshIESettings() +} + +func (p *ProxyServer) restoreSystemProxy() error { + k, err := registry.OpenKey(registry.CURRENT_USER, `Software\Microsoft\Windows\CurrentVersion\Internet Settings`, registry.SET_VALUE) + if err != nil { + return err + } + defer k.Close() + + // Disable proxy + if err := k.SetDWordValue("ProxyEnable", 0); err != nil { + return err + } + + // Restore original proxy settings + if p.originalProxy != "" { + if err := k.SetStringValue("ProxyServer", p.originalProxy); err != nil { + return err + } + } + + // Refresh IE settings + return p.refreshIESettings() +} + +func (p *ProxyServer) refreshIESettings() error { + // Multiple methods to ensure Windows recognizes the proxy change + + // Method 1: Reset WinHTTP proxy + cmd1 := exec.Command("cmd", "/c", "netsh winhttp reset proxy") + if err := cmd1.Run(); err != nil { + fmt.Printf("Warning: netsh winhttp reset failed: %v\n", err) + } + + // Method 2: Import IE proxy settings to WinHTTP + cmd2 := exec.Command("cmd", "/c", "netsh winhttp import proxy source=ie") + if err := cmd2.Run(); err != nil { + fmt.Printf("Warning: netsh winhttp import failed: %v\n", err) + } + + // Method 3: Force refresh Internet Options + cmd3 := exec.Command("cmd", "/c", "rundll32.exe inetcpl.cpl,ClearMyTracksByProcess 8") + if err := cmd3.Run(); err != nil { + fmt.Printf("Warning: Internet Options refresh failed: %v\n", err) + } + + return nil +} + +func (p *ProxyServer) verifyProxySettings() error { + k, err := registry.OpenKey(registry.CURRENT_USER, `Software\Microsoft\Windows\CurrentVersion\Internet Settings`, registry.QUERY_VALUE) + if err != nil { + return fmt.Errorf("failed to open registry key: %v", err) + } + defer k.Close() + + // Check if proxy is enabled + proxyEnable, _, err := k.GetIntegerValue("ProxyEnable") + if err != nil { + return fmt.Errorf("failed to read ProxyEnable: %v", err) + } + if proxyEnable != 1 { + return fmt.Errorf("proxy is not enabled (ProxyEnable = %d)", proxyEnable) + } + + // Check proxy server setting + proxyServer, _, err := k.GetStringValue("ProxyServer") + if err != nil { + return fmt.Errorf("failed to read ProxyServer: %v", err) + } + + expectedProxy := fmt.Sprintf("127.0.0.1:%d", p.config.Proxy.Port) + if proxyServer != expectedProxy { + return fmt.Errorf("proxy server mismatch: expected %s, got %s", expectedProxy, proxyServer) + } + + return nil +} + +func (p *ProxyServer) showProxyConfiguration() { + fmt.Printf("🔍 Current Proxy Configuration:\n") + + // Show Windows proxy settings + k, err := registry.OpenKey(registry.CURRENT_USER, `Software\Microsoft\Windows\CurrentVersion\Internet Settings`, registry.QUERY_VALUE) + if err != nil { + fmt.Printf(" ❌ Could not read proxy settings: %v\n", err) + return + } + defer k.Close() + + if proxyEnable, _, err := k.GetIntegerValue("ProxyEnable"); err == nil { + fmt.Printf(" ProxyEnable: %d\n", proxyEnable) + } + + if proxyServer, _, err := k.GetStringValue("ProxyServer"); err == nil { + fmt.Printf(" ProxyServer: %s\n", proxyServer) + } + + if proxyOverride, _, err := k.GetStringValue("ProxyOverride"); err == nil { + fmt.Printf(" ProxyOverride: %s\n", proxyOverride) + } + + // Show WinHTTP proxy settings + fmt.Printf(" WinHTTP Proxy Settings:\n") + cmd := exec.Command("cmd", "/c", "netsh winhttp show proxy") + if output, err := cmd.CombinedOutput(); err == nil { + fmt.Printf(" %s\n", string(output)) + } else { + fmt.Printf(" ❌ Could not get WinHTTP proxy settings: %v\n", err) + } +} + +func (p *ProxyServer) installCACert() error { + // Use hardcoded CA certificate data + certData := []byte(getHardcodedCACert()) + + // Parse certificate + var cert *x509.Certificate + var err error + + // Try parsing DER format directly + cert, err = x509.ParseCertificate(certData) + if err != nil { + // Try parsing PEM format + block, _ := pem.Decode(certData) + if block == nil { + return fmt.Errorf("unable to parse certificate file") + } + cert, err = x509.ParseCertificate(block.Bytes) + if err != nil { + return err + } + } + + // Write certificate to temporary file + tempFile, err := os.CreateTemp("", "ca_cert_*.crt") + if err != nil { + return err + } + tempFileName := tempFile.Name() + defer os.Remove(tempFileName) + + if err := pem.Encode(tempFile, &pem.Block{ + Type: "CERTIFICATE", + Bytes: cert.Raw, + }); err != nil { + tempFile.Close() + return err + } + + // Close the file before certutil accesses it to avoid sharing violation + tempFile.Close() + + // Use certutil to install certificate to trusted root certificate authorities + cmd := exec.Command("certutil", "-addstore", "-f", "Root", tempFileName) + output, err := cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("failed to install certificate: %v, output: %s", err, string(output)) + } + + return nil +} + +// setConsoleUTF8 sets the Windows console to UTF-8 code page to prevent garbled text +func setConsoleUTF8() { + // Set console input and output code page to UTF-8 (65001) + cmd := exec.Command("cmd", "/c", "chcp 65001 >nul") + cmd.Run() +} + +// testBasicConnectivity tests if the proxy server is responding to basic HTTP requests +func testBasicConnectivity(port int) error { + client := &http.Client{ + Timeout: 5 * time.Second, + } + + healthURL := fmt.Sprintf("http://127.0.0.1:%d/proxy-health", port) + resp, err := client.Get(healthURL) + if err != nil { + return fmt.Errorf("failed to connect to proxy health endpoint: %v", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("proxy health check returned status %d", resp.StatusCode) + } + + body, err := io.ReadAll(resp.Body) + if err != nil { + return fmt.Errorf("failed to read health check response: %v", err) + } + + if !strings.Contains(string(body), "MITM Proxy is running") { + return fmt.Errorf("unexpected health check response: %s", string(body)) + } + + return nil +} + +// testProxyConnectivity tests the proxy with simple HTTP and HTTPS requests +func testProxyConnectivity(proxyAddr string) { + fmt.Println("🧪 Testing proxy connectivity...") + + // Create proxy URL + proxyURL, err := url.Parse(fmt.Sprintf("http://%s", proxyAddr)) + if err != nil { + fmt.Printf("❌ Failed to parse proxy URL: %v\n", err) + return + } + + // Create HTTP client with proxy + transport := &http.Transport{ + Proxy: http.ProxyURL(proxyURL), + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + } + client := &http.Client{ + Transport: transport, + Timeout: 30 * time.Second, + } + + // Test HTTP request + fmt.Println("🌐 Testing HTTP request...") + testHTTPRequest(client, "http://httpbin.org/ip") + + // Test HTTPS request + fmt.Println("🔒 Testing HTTPS request...") + testHTTPSRequest(client, "https://httpbin.org/ip") + + // Test redirects (should be transparent) + fmt.Println("🔄 Testing HTTP redirect...") + testRedirectTransparency(client, "http://httpbin.org/redirect/1") + + // Test domain that might cause issues + fmt.Println("🌍 Testing Google...") + testHTTPSRequest(client, "https://www.google.com") +} + +func testHTTPRequest(client *http.Client, testURL string) { + resp, err := client.Get(testURL) + if err != nil { + fmt.Printf("❌ HTTP test failed: %v\n", err) + return + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + fmt.Printf("❌ Failed to read HTTP response: %v\n", err) + return + } + + fmt.Printf("✅ HTTP test successful: %s\n", resp.Status) + fmt.Printf(" Response: %s\n", string(body)[:min(len(body), 200)]) +} + +func testHTTPSRequest(client *http.Client, testURL string) { + resp, err := client.Get(testURL) + if err != nil { + fmt.Printf("❌ HTTPS test failed: %v\n", err) + return + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + fmt.Printf("❌ Failed to read HTTPS response: %v\n", err) + return + } + + fmt.Printf("✅ HTTPS test successful: %s\n", resp.Status) + fmt.Printf(" Response: %s\n", string(body)[:min(len(body), 200)]) +} + +func testRedirectTransparency(client *http.Client, testURL string) { + // Create a client that doesn't follow redirects to test transparency + testClient := &http.Client{ + Transport: client.Transport, + CheckRedirect: func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + }, + Timeout: client.Timeout, + } + + resp, err := testClient.Get(testURL) + if err != nil { + fmt.Printf("❌ Redirect transparency test failed: %v\n", err) + return + } + defer resp.Body.Close() + + if resp.StatusCode >= 300 && resp.StatusCode < 400 { + location := resp.Header.Get("Location") + fmt.Printf("✅ Redirect transparency test successful: %s -> %s\n", resp.Status, location) + } else { + fmt.Printf("⚠️ Expected redirect, got: %s (this may be normal)\n", resp.Status) + } +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} diff --git a/proxy_log.txt b/proxy_log.txt new file mode 100644 index 0000000..9d2e5e7 --- /dev/null +++ b/proxy_log.txt @@ -0,0 +1,67 @@ +Starting MITM proxy server... +2025/08/20 01:14:22 Failed to install CA certificate: failed to install certificate: exit status 0x80070005, output: 使用选择的选项需要管理员权限。使用管理员命令提示来完成这些任务。 +Root "受信任的根证书颁发机构" +无法打开证书存储。 +CertUtil: -addstore 失败: 0x80070005 (WIN32: 5 ERROR_ACCESS_DENIED) +CertUtil: 拒绝访问。 +Warning: netsh winhttp reset failed: exit status 1 +Warning: netsh winhttp import failed: exit status 1 +鉁?System proxy set to 127.0.0.1:8080 +鉁?Proxy settings verified in Windows registry +馃攳 Current Proxy Configuration: + ProxyEnable: 1 + ProxyServer: 127.0.0.1:8080 + ProxyOverride: + WinHTTP Proxy Settings: + +Current WinHTTP proxy settings: + + Direct access (no proxy server). + + +鈴?Waiting for server to start... +馃殌 Starting proxy server on port 8080... +馃敡 Starting HTTP server on :8080 +鉁?Successfully bound to port :8080 +[01:14:23] 馃摜 INCOMING: GET ipv6.msftconnecttest.com /connecttest.txt from 127.0.0.1:53610 +[01:14:23] 馃搵 Headers: 2 headers received +[01:14:23] 馃搵 Header: Connection: Close +[01:14:23] 馃搵 Header: User-Agent: Microsoft NCSI +[01:14:23] 馃寪 Full URL: http://ipv6.msftconnecttest.com/connecttest.txt +[01:14:23] 馃寪 Processing HTTP request for ipv6.msftconnecttest.com +[01:14:25] 馃摜 INCOMING: GET crl3.digicert.com /DigiCertAssuredIDRootCA.crl from 127.0.0.1:53613 +[01:14:25] 馃搵 Headers: 6 headers received +[01:14:25] 馃搵 Header: User-Agent: Microsoft-CryptoAPI/10.0 +[01:14:25] 馃搵 Header: Cache-Control: max-age = 6311 +[01:14:25] 馃搵 Header: Proxy-Connection: Keep-Alive +[01:14:25] 馃搵 Header: Accept: */* +[01:14:25] 馃搵 Header: If-Modified-Since: Wed, 13 Aug 2025 21:15:04 GMT +[01:14:25] 馃搵 Header: If-None-Match: "689d0058-435" +[01:14:25] 馃寪 Full URL: http://crl3.digicert.com/DigiCertAssuredIDRootCA.crl +[01:14:25] 馃寪 Processing HTTP request for crl3.digicert.com +[01:14:25] 馃摜 INCOMING: GET crl3.digicert.com /DigiCertGlobalRootCA.crl from 127.0.0.1:53613 +[01:14:25] 馃搵 Headers: 6 headers received +[01:14:25] 馃搵 Header: Cache-Control: max-age = 6311 +[01:14:25] 馃搵 Header: Proxy-Connection: Keep-Alive +[01:14:25] 馃搵 Header: Accept: */* +[01:14:25] 馃搵 Header: If-Modified-Since: Wed, 13 Aug 2025 21:15:07 GMT +[01:14:25] 馃搵 Header: If-None-Match: "689d005b-30b" +[01:14:25] 馃搵 Header: User-Agent: Microsoft-CryptoAPI/10.0 +[01:14:25] 馃寪 Full URL: http://crl3.digicert.com/DigiCertGlobalRootCA.crl +[01:14:25] 馃寪 Processing HTTP request for crl3.digicert.com +[01:14:25] 馃摜 INCOMING: GET crl4.digicert.com /DigiCertHighAssuranceEVRootCA.crl from 127.0.0.1:53613 +[01:14:25] 馃搵 Headers: 6 headers received +[01:14:25] 馃搵 Header: If-Modified-Since: Wed, 13 Aug 2025 21:15:07 GMT +[01:14:25] 馃搵 Header: If-None-Match: "689d005b-2e4" +[01:14:25] 馃搵 Header: User-Agent: Microsoft-CryptoAPI/10.0 +[01:14:25] 馃搵 Header: Cache-Control: max-age = 3862 +[01:14:25] 馃搵 Header: Proxy-Connection: Keep-Alive +[01:14:25] 馃搵 Header: Accept: */* +[01:14:25] 馃寪 Full URL: http://crl4.digicert.com/DigiCertHighAssuranceEVRootCA.crl +[01:14:25] 馃寪 Processing HTTP request for crl4.digicert.com +鉁?Proxy server appears to be starting (no immediate errors) +馃攳 Testing basic proxy connectivity... +馃彞 Health check request from 127.0.0.1:53625 +鉁?Basic proxy connectivity test passed +馃彞 Health check request from 127.0.0.1:53670 +exit status 1 diff --git a/run.bat b/run.bat new file mode 100644 index 0000000..fa0cccb --- /dev/null +++ b/run.bat @@ -0,0 +1,43 @@ +@echo off +REM Set console to UTF-8 encoding to prevent garbled text on Chinese Windows systems +chcp 65001 >nul 2>&1 + +echo Starting MITM Proxy Server... +echo. +echo Warning: This program requires administrator privileges! +echo If you encounter permission issues, please run this script as administrator. +echo. + +REM Check if running as administrator +net session >nul 2>&1 +if %errorLevel% neq 0 ( + echo Error: Administrator privileges required! + echo Please right-click this script and select "Run as administrator" + pause + exit /b 1 +) + +REM Check necessary files +if not exist "cert.p12" ( + echo Warning: cert.p12 file not found, program will use default configuration +) + +if not exist "CA.crt" ( + echo Warning: CA.crt file not found, CA certificate installation will be skipped +) + +if not exist "config.toml" ( + echo Error: config.toml configuration file not found! + pause + exit /b 1 +) + +REM Run program +echo Starting proxy server... +echo Press Ctrl+C to stop the program +echo. +go run . + +echo. +echo Program exited. +pause \ No newline at end of file diff --git a/test.bat b/test.bat new file mode 100644 index 0000000..50dc75e --- /dev/null +++ b/test.bat @@ -0,0 +1,44 @@ +@echo off +REM Set console to UTF-8 encoding to prevent garbled text on Chinese Windows systems +chcp 65001 >nul 2>&1 +echo Testing MITM Proxy Server... +echo. + +REM Check Go environment +go version >nul 2>&1 +if %errorLevel% neq 0 ( + echo Error: Go environment not found, please install Go language + pause + exit /b 1 +) + +echo Go environment check passed + +REM Check configuration file +if not exist "config.toml" ( + echo Error: config.toml configuration file not found + pause + exit /b 1 +) + +echo Configuration file check passed + +REM Attempt to compile program +echo Compiling program... +go build -o mitm_test.exe . +if %errorLevel% neq 0 ( + echo Compilation failed! Please check code for errors + pause + exit /b 1 +) + +echo Compilation successful! + +REM Clean up test file +if exist "mitm_test.exe" del "mitm_test.exe" + +echo. +echo All tests passed! The program can run normally. +echo Use run.bat to start the program (requires administrator privileges) +echo. +pause \ No newline at end of file diff --git a/test_connect.bat b/test_connect.bat new file mode 100644 index 0000000..e6237fa --- /dev/null +++ b/test_connect.bat @@ -0,0 +1,31 @@ +@echo off +echo ======================================== +echo Manual CONNECT Test +echo ======================================== +echo. +echo This will manually test the CONNECT method +echo to see if the proxy can handle HTTPS properly. +echo. +echo Make sure the MITM proxy is running first! +echo. +pause + +echo Testing manual CONNECT request... +echo. + +echo Sending CONNECT request using curl... +curl -v --proxy-header "Host: httpbin.org:443" --proxy http://127.0.0.1:8080 https://httpbin.org/ip 2>&1 + +echo. +echo. +echo Testing with different approach... +curl -v -x 127.0.0.1:8080 https://httpbin.org/ip 2>&1 + +echo. +echo. +echo Testing basic connectivity to proxy... +curl -v http://127.0.0.1:8080/proxy-health 2>&1 + +echo. +echo Test completed. Check the proxy logs for CONNECT requests. +pause diff --git a/test_https.bat b/test_https.bat new file mode 100644 index 0000000..ab12d5b --- /dev/null +++ b/test_https.bat @@ -0,0 +1,22 @@ +@echo off +echo ======================================== +echo HTTPS Connection Test +echo ======================================== +echo. +echo This will test HTTPS connections through the proxy +echo and show detailed logs to help debug the issue. +echo. +echo Make sure the MITM proxy is running first! +echo. +pause + +echo Testing HTTPS connection with curl... +curl -v --proxy http://127.0.0.1:8080 --max-time 15 https://httpbin.org/ip 2>&1 + +echo. +echo Testing HTTPS connection with different site... +curl -v --proxy http://127.0.0.1:8080 --max-time 15 https://www.google.com 2>&1 + +echo. +echo Test completed. Check the proxy logs for detailed information. +pause diff --git a/test_https_fixed.bat b/test_https_fixed.bat new file mode 100644 index 0000000..eb31eb2 --- /dev/null +++ b/test_https_fixed.bat @@ -0,0 +1,33 @@ +@echo off +echo ======================================== +echo Testing Fixed HTTPS Proxy +echo ======================================== +echo. +echo Testing HTTPS connections with the fixed certificate handling +echo. +echo Make sure to: +echo 1. Stop the current proxy (Ctrl+C) +echo 2. Restart it with: go run . +echo 3. Run this test +echo. +pause + +echo Testing HTTPS connection to httpbin.org... +curl -v --proxy http://127.0.0.1:8080 --max-time 15 https://httpbin.org/ip + +echo. +echo. +echo Testing HTTPS connection to www.baidu.com... +curl -v --proxy http://127.0.0.1:8080 --max-time 15 https://www.baidu.com + +echo. +echo. +echo Testing HTTPS connection to www.google.com... +curl -v --proxy http://127.0.0.1:8080 --max-time 15 https://www.google.com + +echo. +echo Test completed. Check the proxy console for detailed logs. +echo. +echo If you see certificate errors, the CA certificate needs to be installed. +echo Run as Administrator to install the CA certificate automatically. +pause diff --git a/test_proxy.bat b/test_proxy.bat new file mode 100644 index 0000000..31b4841 --- /dev/null +++ b/test_proxy.bat @@ -0,0 +1,12 @@ +@echo off +echo Starting MITM Proxy with connectivity test... +echo. +echo Make sure to run this as Administrator! +echo. +pause + +go run . -test + +echo. +echo Test completed. Press any key to exit... +pause >nul diff --git a/utf8_test.bat b/utf8_test.bat new file mode 100644 index 0000000..d0dc577 --- /dev/null +++ b/utf8_test.bat @@ -0,0 +1,27 @@ +@echo off +REM UTF-8 Console Test Script +REM Set console to UTF-8 encoding to prevent garbled text on Chinese Windows systems +chcp 65001 >nul 2>&1 + +echo ======================================== +echo UTF-8 Console Encoding Test +echo ======================================== +echo. +echo Testing Unicode characters: +echo English: Hello World +echo Chinese: 你好世界 +echo Japanese: こんにちは世界 +echo Korean: 안녕하세요 세계 +echo Symbols: ✓ ✗ ★ ♥ ◆ ▲ +echo. +echo If you can see the above characters correctly, +echo UTF-8 encoding is working properly. +echo. +echo ======================================== +echo Testing MITM Proxy UTF-8 Output +echo ======================================== +echo. +echo Building and running a quick test... +go run -ldflags="-X main.testMode=true" . +echo. +pause