Post

Write-up — 3v@l

Uncover a critical eval() vulnerability in a mock "ABC Bank" loan calculator! This in-depth CTF walkthrough guides you through discovering Remote Code Execution (RCE) on a Python backend, bypassing keyword filters with Base64 encoding, and successfully exploiting the system. Perfect for anyone learning web application security, ethical hacking, or vulnerability management. Learn practical exploitation techniques step-by-step and strengthen your cybersecurity skills!

Write-up — 3v@l

Walkthrough of ctf 3v@l from picoCTF :

https://play.picoctf.org/practice?category=1&originalEvent=74&page=1&search=3v%40l

Description

ABC Bank’s website has a loan calculator to help its clients calculate the amount they pay if they take a loan from the bank. Unfortunately, they are using an eval function to calculate the loan. Bypassing this will give you Remote Code Execution (RCE). Can you exploit the bank’s calculator and read the flag? Additional details will be available after launching your challenge instance.


Solution

Imagine you’re on ABC Bank’s website. They have a tool that helps you figure out how much a loan would cost. Seems safe, right? But the challenge told us something important: the website uses a special function called eval behind the scenes. This eval function can be very risky. If it’s not used carefully, someone could run their own code on the bank’s computer! Our goal was to do just that – find a way to run our code and read a secret file called /flag.txt.

Step 1: Testing the Waters - What is eval()?

You were right from the start: eval() takes a piece of text and tries to run it as computer code. If a website takes what you type in and uses it directly in eval(), it means you can send commands for the server to run!

To begin, you simply need to try things out. What happens if you type something that isn’t just a number into the calculator? You’re basically asking the eval() function to show you how it works.

Step 2: Reading the Clues - Discovering Python!

When you put in some unusual text, you got an error message that was really helpful: name 'ksfv' is not defined. This might look like a problem, but it was actually a big hint!

That exact error message, name '...' is not defined, is a common sign you’re dealing with a Python program. So, right away, you knew what language the bank’s website was using. The ksfv part just showed that your input was being processed as Python code. The main thing here was figuring out the programming language.

Step 3: Finding the Blocks - Security Filters!

Next, you smartly checked the website’s secret code (the source code). You found a note that looked like this:

1
2
3
4
5
6
7
8
<!--
    TODO
    ------------
    Secure python_flask eval execution by
1.blocking malcious keyword like os,eval,exec,bind,connect,python,socket,ls,cat,shell,bind

2.Implementing regex: r'0x[0-9A-Fa-f]+|\\u[0-9A-Fa-f]{4}|%[0-9A-Fa-f]{2}|\.[A-Za-z0-9]{1,3}\b|[\\\/]|\.\.'
-->

This confirmed it was Python and, even better, it told you exactly which words the developers were trying to stop people from using. Words like os, eval, exec, ls, and cat were on the forbidden list. This meant you couldn’t just type os.system('cat /flag.txt'). You needed a new plan!

Step 4: Getting Around the Blocks with Encoding

Since cat (and other useful commands) were blocked, you needed a different way to read the file. You couldn’t just type cat. This is where encoding becomes a clever trick to get past filters! Here’s the idea:

  1. Take the command you want to run, like cat /flag.txt.
  2. Change it into a secret code, like Base64. For cat /flag.txt, the Base64 version looks like Y2F0IC9mbGFnLnR4dA==. The website’s filter won’t see “cat” in that jumble of letters and numbers.
  3. In your Python code, you’ll then use a special function to decode this Base64 text back into the original command.
  4. Then, you tell the computer to run that un-coded command.

Step 5: Building Your Special Command

Now for the final step: creating the perfect single line of Python code that the eval() function would run without problems. This special line needed to do a few things:

  • Bring in other Python tools (like subprocess for running commands and base64 for decoding) without using the normal import word, because eval() expects something different.
  • Un-code your Base64 message.
  • Run that command and show you what it found (the flag!).

And here’s the smart command you came up with:

1
__import__("subprocess").getoutput(__import__("base64").b64decode('Y2F0IC9mbGFnLnR4dA=='))

Let’s see how this powerful line works:

  • __import__("subprocess"): This is a clever Python way to get the subprocess tool ready to use.
  • __import__("base64"): This does the same for the base64 tool, which has the un-coding function.
  • .b64decode('Y2F0IC9mbGFnLnR4dA=='): This takes your Base64 code (Y2F0IC9mbGFnLnR4dA==) and perfectly turns it back into cat /flag.txt.
  • .getoutput(...): Finally, this runs the cat /flag.txt command and collects whatever it finds – which should be the secret flag!

When you put this into the loan calculator, the eval() function ran it, the command worked, and you saw the flag!

This post is licensed under CC BY 4.0 by the author.