First and foremost, this article is based on my real-world bug-hunting experience. At the time of writing, the vendor has already patched the vulnerability, and the issue was responsibly disclosed to Butian. This article does not involve any conflicts of interest, and the code provided has been sanitized (e.g., URLs modified). It is purely a summary of my bug-hunting journey and a technical sharing session. Please take note!

Spending my sophomore summer on campus was quite dull, so I spent my time bug-hunting and coding. While it might seem monotonous, it was actually quite enjoyable. Readers of my blog might recall a previous post where I analyzed a âcoupon exploitationâ technique. If you havenât read it yet, I recommend checking it out, as itâs somewhat related to this article.
A Practical Guide to Coupon Exploitation: From Packet Capturing to Script Automation
Letâs skip the fluff and dive straight into the bug-hunting process.
If youâve ever used a car-sharing service, youâd know that because these services are still in the promotional phase, companies often provide new users with various coupons, such as time-free coupons or no-threshold monetary discounts. This article begins with these coupons, where I discovered multiple logical vulnerabilities. By combining these vulnerabilities, I managed to drive a shared car for free.

But my thought process wasnât limited to just this. I began wonderingâcould there be privilege escalation vulnerabilities in the coupon system? Perhaps my obsession with the previous coupon exploitation code led me to this idea. While capturing packets, I noticed that every time an order was paid, the client would request the current coupon information from the server. The app categorized coupons into two types: usable and unusable for the current order.
After analyzing the packets, I discovered that whether a coupon could be used was determined entirely by the client. The server simply sent categorized coupons (usable and unusable) to the client. During checkout, all coupons were displayed, but those not meeting the order conditions could not be selectedâfor example, expired coupons.

Clearly, expired coupons could not be used during checkout. So, my approach was to capture packets and directly replace or add multiple expired coupon IDs. For demonstration purposes, I modified the packets in an emulator.

I selected a 7-day short-term rental package. Since my account had no usable coupons, the `newCouponList` was empty. At this point, I inserted multiple expired coupon IDs recorded earlier and resent the packet.

As you can see, the order amount decreased.
The total dropped from 896 to 750. At this point, I could proceed to pay for the order. But donât think the discount stops here. I only added two coupon IDs. If you have enough coupons (expired or not), you can keep adding them until the order reaches its minimum amount.

However, no matter how many coupons you use, the order amount will never reach zero. This means thereâs a minimum payable amount for every order.
During my tests, I found that when the coupon value exceeded the rental fee, it could only offset the rental fee, leaving basic service fees untouched. Still, such logical vulnerabilities could lead to significant financial losses.
Although the front-end restricted the use of one coupon per order, the back-end did not validate this, allowing multiple coupon IDs to be combined.

But do you think thatâs the end of it? Not quite. Thereâs an even more insidious privilege escalation vulnerability: using coupon IDs from other accounts. The testing method is straightforward. Suppose I have two accounts, A and B. Using the same method, I captured packets with account A and replaced the coupon ID with one from account B. Testing confirmed that this worked as well. I wonât demonstrate this here, but itâs even more devious.

If the above methods donât allow for completely free usage, letâs consider another angle. Car rentals are divided into two modes: short-term and shared. While short-term rentals have basic service fees, shared rentals do not. The principle remains the same.
The most outrageous part? The same coupon ID can be reused repeatedly.

This is a screenshot of a shared car order payment during the summer. Since thereâs a 10-minute window between order completion and payment, you can execute the above steps within that timeframe to achieve a $0 payment and effectively drive the car for free.
But do you think Iâd go through all this trouble manually capturing packets?
Of course not. As a penetration tester, why not automate the process?
Naturally, I wrote a Python script to automate the exploitation of these privilege escalation vulnerabilities. Packet capturing was only for analyzing the business logic vulnerabilities. Below is a sanitized version of the payload I wrote. Note that the code is not well-optimized, but it worksâso donât judge!
payload1.py
The content provided appears to be a detailed walkthrough of exploiting business logic vulnerabilities in a shared car rental platform. Below is the translated version of the text content, keeping the original formatting, HTML tags, and styles intact:
â
The two payloads above are used in combination. Think about it: if you want to replace the coupon ID without capturing packets manually, you must complete the login process using a script. My exploitation idea is to log into the account using a script, locate unpaid orders in the account, replace the coupon ID, and complete the payment process. As mentioned earlier, their business logic allows a 10-minute window for payment after an order is completed. If payment is not manually completed within 10 minutes, the system automatically initiates a deduction through Alipay to complete the payment. I used PHP to receive parameters and then called the Python script to execute the process, which involved overcoming several challenges.
Some challenges encountered when calling Python scripts from PHP
So, we can deploy the payload to a server, create a simple front-end page to receive parameters, pass them to the backend, and let Python handle the process to exploit the vulnerability. This essentially creates an interface, allowing me to enjoy the exploit every time I finish using a car.
Some might ask: how do you handle both the image captcha and the SMS verification code during account login?
- For the image captcha, I wrote an anonymous function to perform binarization and then used OCR for recognition. Their captcha was very simple, and after binarization, the OCR recognition rate was nearly 99%, so there were no issues.
- As for the SMS verification code, this is why I split the process into two payloads. There is a user interaction step where the user needs to input the verification code. Payload1.py triggers the verification code and writes the cookie to a text file. Payload2.py reads the previously saved cookie and the userâs verification code to complete the login logic and payment process.
As a result, I managed to exploit the system and enjoy free shared car rides for half a month. I also submitted these vulnerabilities to the Bug Bounty platform.
Hereâs another example of such vulnerabilities:

So, do you think it ends here?
After they patched the vulnerabilities, it seemed like the exploit was no longer possible. However, I realized their developers hadnât fully addressed the issue.
As I mentioned earlier, this exploit relied on combining multiple logical vulnerabilities. Their developers only patched the issue where the coupon ID could be reused, but they didnât fix the privilege escalation vulnerability. This was merely treating the symptoms, not the root cause.
So, the next day, I came up with an even more creative approach. I used a virtual SMS platform to register a bunch of fake accounts. According to their business logic, newly registered users are automatically granted coupons, regardless of whether the user has completed real-name authentication.
I was genuinely baffled by the developersâ logic. I guess they thought: âAs long as the user registers with a phone number, weâll issue coupons. If they havenât completed real-name authentication, they canât use the coupons anyway.â However, they completely overlooked privilege escalation issues, allowing me to use coupons from other usersâ accounts.

Same old wine in a new bottle!
And so, I continued exploiting the system, having a good laugh.
However, after a few days, they seemed to have discovered the issue and patched the privilege escalation vulnerability as well. But it was quite an interesting experience.
To summarize, hereâs a breakdown of the logical vulnerabilities exploited:
- The server did not validate whether the coupon was applicable to the specific order (e.g., shared or short-term rental).
- The server did not validate the couponâs status (e.g., whether it had expired).
- The server did not validate whether the coupon belonged to the user.
- The server did not limit the number of coupons that could be used for a single order.
- The same coupon could be reused repeatedly (regardless of expiration status).
- Newly registered users were issued coupons without requiring real-name authentication.
By combining these six logical vulnerabilities, I was able to exploit the system and enjoy free shared car rides.
I believe that when it comes to vulnerability hunting, we shouldnât limit ourselves to traditional issues like XSS or SQL injection. Often, exploring business logic can uncover many interesting vulnerabilities, haha.
PS: Although these vulnerabilities might seem simple, finding them in real-world scenarios is not as easy as it seems. These were real-world vulnerabilities. During the summer, I sat on the sidewalk of Zhongxin Avenue opposite my school with my laptop. Since shared cars are parked on the roadside, I had to be near the car to complete the payment logic. To capture packets, I turned on my phoneâs hotspot and squatted on the street for an entire morning. Passersby looked at me like I was crazy, but who cares? Just focus on your own work.