Tag: cybersecurity

  • Using .htaccess file to compromise loose ext control upload in php

    Imagine this: You’ve just launched a new feature on your website allowing users to upload profile pictures. Everything seems fine until one day, your server is compromised, and malicious scripts are running wild. The culprit? A seemingly harmless .htaccess file lurking in your upload directory. This isn’t just a hypothetical scenario—it’s a common attack vector that exploits misconfigured .htaccess files and loose file extension controls in PHP. Let’s break down how this happens, how attackers exploit it, and most importantly, how you can protect your application.

    What is the .htaccess File and Why Does It Matter?

    The .htaccess file is a configuration file used by the Apache web server to control directory-level settings. It’s incredibly powerful, allowing you to manage redirects, set custom error pages, enable or disable directory indexing, and even define how specific file extensions are handled. For PHP applications, .htaccess can dictate which file extensions are treated as executable PHP scripts.

    For example, you might use the following directive to tell Apache to treat files with extensions like .php5 or .phtml as PHP scripts:

    AddType application/x-httpd-php .php .php5 .phtml

    While this flexibility is convenient, it’s also a double-edged sword. Attackers can exploit misconfigured .htaccess files to execute arbitrary code, bypass security measures, or expose sensitive data. Before diving into the specifics, let’s talk about the security implications of allowing users to upload files to your server.

    🔐 Security Note: File uploads are inherently risky. Always assume that any file uploaded by a user could be malicious. Validate, sanitize, and restrict uploads to the bare minimum necessary for your application.

    How Attackers Exploit .htaccess in Upload Directories

    When you allow users to upload files, you’re essentially giving them a way to place content on your server. If your upload directory isn’t properly secured, attackers can upload malicious files and use .htaccess to weaponize them. Here are some common attack scenarios:

    1. Executing Arbitrary Code

    One of the most dangerous exploits involves using .htaccess to treat non-PHP files as PHP scripts. For example, an attacker could upload a file named malicious.jpg containing PHP code and then add the following directive to the upload directory’s .htaccess file:

    AddType application/x-httpd-php .jpg

    This tells Apache to process .jpg files as PHP scripts. The attacker can then execute their malicious code simply by accessing malicious.jpg via a browser.

    ⚠️ Gotcha: Even if you restrict uploads to certain file types (e.g., images), this won’t stop an attacker from embedding PHP code in a file with a valid extension like .jpg or .png.

    2. Exposing Directory Contents

    By default, Apache may block directory indexing, which prevents users from seeing a list of files in a directory. However, an attacker can override this setting by adding the following line to .htaccess:

    Options +Indexes

    This enables directory indexing, allowing anyone who knows the URL of your upload directory to browse its contents. If sensitive files are stored there, they could be exposed to the public.

    3. Overriding Security Settings

    Another common tactic is disabling security features like file execution restrictions. For example, if you’ve configured your server to block PHP execution in the upload directory, an attacker could bypass this by adding a malicious .htaccess file that re-enables PHP execution.

    Best Practices for Securing Upload Directories

    Now that we’ve seen how attackers can exploit .htaccess, let’s discuss how to defend against these attacks. Here are some practical steps you can take to secure your upload directories:

    1. Disable PHP Execution

    The most effective way to prevent attackers from executing malicious PHP code in your upload directory is to disable PHP execution entirely. You can do this by creating a .htaccess file in the upload directory with the following content:

    php_flag engine off

    This directive disables the PHP engine for the directory, ensuring that even if an attacker uploads a PHP file, it won’t be executed.

    💡 Pro Tip: If you’re using Nginx instead of Apache, you can achieve the same result by configuring your server block to deny PHP execution in the upload directory.

    2. Restrict File Types

    Limit the types of files that can be uploaded to your server. For example, if your application only needs to accept images, restrict uploads to common image formats like .jpg, .png, and .gif. Here’s a simple PHP example:

    // Validate uploaded file type
    $allowed_types = ['image/jpeg', 'image/png', 'image/gif'];
    if (!in_array($_FILES['uploaded_file']['type'], $allowed_types)) {
        die('Invalid file type.');
    }
    

    3. Validate and Sanitize File Names

    Always sanitize file names to prevent directory traversal attacks or other exploits. For example:

    // Sanitize file name
    $filename = basename($_FILES['uploaded_file']['name']);
    $sanitized_filename = preg_replace('/[^a-zA-Z0-9._-]/', '', $filename);
    move_uploaded_file($_FILES['uploaded_file']['tmp_name'], '/uploads/' . $sanitized_filename);
    

    4. Use a Separate Domain or Subdomain

    Consider serving uploaded files from a separate domain or subdomain. This isolates the upload directory from your main application, reducing the risk of cross-site scripting (XSS) or other attacks.

    5. Monitor and Audit

    Regularly monitor your upload directories for suspicious activity. Set up alerts for unusual file types or changes to .htaccess files. Automated tools like file integrity monitors can help you detect unauthorized modifications.

    Before You Go Live: Testing Your Configuration

    Before deploying your application, thoroughly test your upload functionality and security measures. Here’s a checklist to get you started:

    • Attempt to upload a PHP file and verify that it cannot be executed.
    • Test your file type validation by uploading unsupported file types.
    • Check your .htaccess settings to ensure PHP execution is disabled.
    • Verify that directory indexing is turned off.
    🔐 Security Note: Always test your application in a staging environment before deploying changes to production.

    Conclusion

    The .htaccess file is a powerful tool for managing PHP file extensions and directory-level settings, but it must be used with caution. Misconfigurations can turn your upload directory into a playground for attackers, exposing your server to serious risks.

    To recap, here are the key takeaways:

    • Disable PHP execution in upload directories to prevent code execution attacks.
    • Restrict uploads to specific file types and validate file names.
    • Use a separate domain or subdomain for serving uploaded files.
    • Regularly monitor and audit your upload directories for suspicious activity.
    • Test your security measures thoroughly before going live.

    By following these best practices, you can significantly reduce the risk of .htaccess-based attacks and keep your application secure. What other strategies have you used to secure file uploads? Share your insights in the comments below!

  • Calculate the SHA-256 hash of a string in JavaScript without library

    Ever wondered how to generate a SHA-256 hash in JavaScript without relying on external libraries? This post walks you through a pure JavaScript implementation of the SHA-256 algorithm, helping you understand each step and the underlying logic.

    The SHA-256 (Secure Hash Algorithm 256) is a widely used cryptographic hash function that produces a fixed-size output for any given input. It is commonly used to verify the integrity of data. In this post, we will learn how to implement the SHA-256 hash function in JavaScript without using any external libraries.

    function sha256(string) {
      // Initialize the SHA-256 hash
      var hash = new Uint32Array(8);
      hash[0] = 0x6a09e667;
      hash[1] = 0xbb67ae85;
      hash[2] = 0x3c6ef372;
      hash[3] = 0xa54ff53a;
      hash[4] = 0x510e527f;
      hash[5] = 0x9b05688c;
      hash[6] = 0x1f83d9ab;
      hash[7] = 0x5be0cd19;
    
      // Convert the string to a byte array
      var stringBytes = toUTF8Bytes(string);
    
      // Pad the byte array to a multiple of 64 bytes
      var paddedBytes = padToMultipleOf(stringBytes, 64);
    
      // Process the padded byte array in blocks of 64 bytes
      for (var i = 0; i < paddedBytes.length; i += 64) {
        processBlock(paddedBytes.slice(i, i + 64), hash);
      }
    
      // Return the final hash as a hexadecimal string
      return toHexString(hash);
    }
    

    The hexadecimal values 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, and 0x5be0cd19 are the initial values of the eight 32-bit words used in the SHA-256 algorithm. These values are defined in the SHA-2 standard and serve as the starting state of the hash calculation. They are commonly referred to as the “initial hash values” or the “initial digest.”

    This function calculates the SHA-256 hash of a given string by first initializing the hash with the default initial values, then converting the string to a byte array, padding the byte array to a multiple of 64 bytes, and finally processing the padded byte array in blocks of 64 bytes.

    The toUTF8Bytes, padToMultipleOf, processBlock, and toHexString functions are helper functions used to convert the string to a byte array, pad the byte array, process the blocks of bytes, and convert the final hash to a hexadecimal string, respectively.

    Here are the implementations of these helper functions:

    function toUTF8Bytes(str) {
      var bytes = [];
      for (var i = 0; i < str.length; i++) {
        var codePoint = str.charCodeAt(i);
        if (codePoint < 0x80) {
          bytes.push(codePoint);
        } else if (codePoint < 0x800) {
          bytes.push(0xc0 | codePoint >> 6);
          bytes.push(0x80 | codePoint & 0x3f);
        } else if (codePoint < 0x10000) {
          bytes.push(0xe0 | codePoint >> 12);
          bytes.push(0x80 | codePoint >> 6 & 0x3f);
          bytes.push(0x80 | codePoint & 0x3f);
        } else {
          bytes.push(0xf0 | codePoint >> 18);
          bytes.push(0x80 | codePoint >> 12 & 0x3f);
          bytes.push(0x80 | codePoint >> 6 & 0x3f);
          bytes.push(0x80 | codePoint & 0x3f);
        }
      }
      return bytes;
    }
    

    This function converts the given string to a UTF-8 encoded byte array by iterating over the string and converting each character to a code point using charCodeAt. It then encodes the code point as a sequence of bytes in the array, depending on the value of the code point. If the code point is less than 0x80, it is encoded as a single byte. If it is between 0x80 and 0x800, it is encoded as two bytes. If it is between 0x800 and 0x10000, it is encoded as three bytes. Otherwise, it is encoded as four bytes. The function returns the resulting byte array.

    Here is the complete implementation of padToMultipleOf and processBlock:

    function padToMultipleOf(bytes, multiple) {
      var padding = bytes.length % multiple;
      if (padding > 0) {
        padding = multiple - padding;
      }
      for (var i = 0; i < padding; i++) {
        bytes.push(i === 0 ? 0x80 : 0x00);
      }
      return bytes;
    }
    
    function processBlock(bytes, hash) {
      // Initialize the word array
      var words = new Uint32Array(64);
      for (var i = 0; i < 64; i++) {
        words[i] = bytes[i * 4] << 24 | bytes[i * 4 + 1] << 16 | bytes[i * 4 + 2] << 8 | bytes[i * 4 + 3];
      }
    
      // Initialize the working variables
      var a = hash[0];
      var b = hash[1];
      var c = hash[2];
      var d = hash[3];
      var e = hash[4];
      var f = hash[5];
      var g = hash[6];
      var h = hash[7];
    
      // Process the words in the block
      for (var i = 0; i < 64; i++) {
        var s0 = rotateRight(a, 2) ^ rotateRight(a, 13) ^ rotateRight(a, 22);
        var maj = (a & b) ^ (a & c) ^ (b & c);
        var t2 = s0 + maj;
        var s1 = rotateRight(e, 6) ^ rotateRight(e, 11) ^ rotateRight(e, 25);
        var ch = (e & f) ^ (~e & g);
        var t1 = h + s1 + ch + K[i] + words[i];
    
        h = g;
        g = f;
        f = e;
        e = d + t1;
        d = c;
        c = b;
        b = a;
        a = t1 + t2;
      }
    
      // Update the hash with the final values of the working variables
      hash[0] += a;
      hash[1] += b;
      hash[2] += c;
      hash[3] += d;
      hash[4] += e;
      hash[5] += f;
      hash[6] += g;
      hash[7] += h;
    }
    

    The padToMultipleOf function pads the given byte array so that its length becomes a multiple of the specified value. It calculates the required padding, adds a 0x80 byte followed by 0x00 bytes as needed, and returns the padded array.

    function padToMultipleOf(bytes, multiple) {
      var padding = bytes.length % multiple;
      if (padding > 0) {
        padding = multiple - padding;
      }
      for (var i = 0; i < padding; i++) {
        bytes.push(i === 0 ? 0x80 : 0x00);
      }
      return bytes;
    }
    

    Implementation of the toHexString helper function:

    function toHexString(hash) {
      var hex = "";
      for (var i = 0; i < hash.length; i++) {
        hex += (hash[i] >>> 0).toString(16);
      }
      return hex;
    }
    

    The toHexString function converts the hash (an array of 32-bit unsigned integers) to a hexadecimal string by iterating over the array and converting each element to its hexadecimal representation.

    Here is an example of how the sha256 function can be used to calculate the SHA-256 hash of a given string:

    var hash = sha256("Hello, world!");
    // The value of "hash" is now "7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069"
    
  • How to make requests via tor in Python

    Why Route HTTP Requests Through Tor?

    Imagine you’re working on a web scraping project, and suddenly, your IP gets blocked. Or maybe you’re building a privacy-focused application where user anonymity is paramount. In both scenarios, Tor can be a game-changer. Tor (The Onion Router) is a network designed to anonymize internet traffic by routing it through multiple servers (or nodes), making it nearly impossible to trace the origin of a request.

    But here’s the catch: using Tor isn’t as simple as flipping a switch. It requires careful setup and an understanding of how to integrate it with your Python code. In this guide, I’ll walk you through two approaches to making HTTP requests via Tor: using the requests library with a SOCKS5 proxy and leveraging the stem library for more advanced control.

    🔐 Security Note: While Tor provides anonymity, it doesn’t encrypt your traffic beyond the Tor network. Always use HTTPS for secure communication.

    Setting Up Tor on Your Machine

    Before diving into the code, you need to ensure that Tor is installed and running on your machine. Here’s how you can do it:

    • Linux: Install Tor using your package manager (e.g., sudo apt install tor on Ubuntu). Start the service with sudo service tor start.
    • Mac: Use Homebrew: brew install tor, then start it with brew services start tor.
    • Windows: Download the Tor Expert Bundle from the official Tor Project website and run the Tor executable.

    By default, Tor runs a SOCKS5 proxy on 127.0.0.1:9050. We’ll use this proxy to route our HTTP requests through the Tor network.

    Method 1: Using the requests Library with a SOCKS5 Proxy

    The simplest way to route your HTTP requests through Tor is by configuring the requests library to use Tor’s SOCKS5 proxy. Here’s how:

    Step 1: Install Required Libraries

    First, ensure you have the requests library installed. If not, install it using pip:

    pip install requests[socks]

    Step 2: Create a Tor Session

    Next, create a function to configure a requests session to use the SOCKS5 proxy:

    import requests
    
    def get_tor_session():
        session = requests.session()
        session.proxies = {
            'http': 'socks5h://127.0.0.1:9050',
            'https': 'socks5h://127.0.0.1:9050'
        }
        return session
    

    Notice the use of socks5h instead of socks5. The socks5h scheme ensures that DNS resolution is performed through the Tor network, adding an extra layer of privacy.

    Step 3: Test Your Tor Session

    To verify that your requests are being routed through Tor, you can make a request to a service that returns your IP address:

    session = get_tor_session()
    response = session.get("http://httpbin.org/ip")
    print("Tor IP:", response.text)
    

    If everything is set up correctly, the IP address returned by httpbin.org should differ from your actual IP address.

    💡 Pro Tip: If you encounter issues, ensure that the Tor service is running and listening on 127.0.0.1:9050. You can check this by running netstat -an | grep 9050 (Linux/Mac) or netstat -an | findstr 9050 (Windows).

    Method 2: Using the stem Library for Advanced Control

    While the requests library with a SOCKS5 proxy is straightforward, it doesn’t give you much control over the Tor connection. For more advanced use cases, such as changing your IP address programmatically, the stem library is a better choice.

    Step 1: Install the stem Library

    Install stem using pip:

    pip install stem

    Step 2: Connect to the Tor Controller

    The Tor controller allows you to interact with the Tor process, such as requesting a new identity. Here’s how to connect to it:

    from stem.control import Controller
    
    with Controller.from_port(port=9051) as controller:
        controller.authenticate(password='your_password')  # Replace with your control port password
        print("Connected to Tor controller")
    

    By default, the Tor control port is 9051. You may need to configure a password in your torrc file to enable authentication.

    ⚠️ Gotcha: If you see an authentication error, ensure that the ControlPort and HashedControlPassword options are set in your torrc file. Restart the Tor service after making changes.

    Step 3: Change Your IP Address

    To request a new IP address, send the SIGNAL NEWNYM command to the Tor controller:

    from stem import Signal
    from stem.control import Controller
    
    with Controller.from_port(port=9051) as controller:
        controller.authenticate(password='your_password')
        controller.signal(Signal.NEWNYM)
        print("Requested new Tor identity")
    

    Step 4: Make a Request via Tor

    Combine the stem library with the requests library to make HTTP requests through Tor:

    import requests
    from stem import Signal
    from stem.control import Controller
    
    def get_tor_session():
        session = requests.session()
        session.proxies = {
            'http': 'socks5h://127.0.0.1:9050',
            'https': 'socks5h://127.0.0.1:9050'
        }
        return session
    
    with Controller.from_port(port=9051) as controller:
        controller.authenticate(password='your_password')
        controller.signal(Signal.NEWNYM)
    
        session = get_tor_session()
        response = session.get("http://httpbin.org/ip")
        print("New Tor IP:", response.text)
    

    Performance Considerations

    Routing requests through Tor can significantly impact performance due to the multiple hops your traffic takes. In my experience, response times can range from 500ms to several seconds, depending on the network’s current load.

    💡 Pro Tip: If performance is critical, consider using a mix of Tor and direct connections, depending on the sensitivity of the data you’re handling.

    Security Implications

    While Tor enhances anonymity, it doesn’t guarantee complete security. Here are some key points to keep in mind:

    • Always use HTTPS to encrypt your data.
    • Be cautious of exit nodes, as they can see unencrypted traffic.
    • Regularly update your Tor installation to patch security vulnerabilities.
    🔐 Security Note: Avoid using Tor for illegal activities. Law enforcement agencies can still trace activity under certain conditions.

    Conclusion

    Integrating Tor into your Python projects can unlock powerful capabilities for anonymity and bypassing restrictions. Here’s a quick recap:

    • Use the requests library with a SOCKS5 proxy for simplicity.
    • Leverage the stem library for advanced control, such as changing your IP address.
    • Always prioritize security by using HTTPS and keeping your Tor installation up to date.

    What use cases are you exploring with Tor? Share your thoughts in the comments below!