# CCCamp CTF 2023

## Desert Dino Dialogue

>  
> Welcome to the "Desert Dino Dialogue" challenge, where you will embark on a
> unique and captivating encounter in the scorching desert. Deep within the
> arid landscape, hidden behind towering mountains, resides a lonely NPC (Non-
> Player Character) like no other—a talking dinosaur longing for a
> conversation.  
>  
> Your task is to engage in an extended conversation with this fascinating
> desert-dweller. The dinosaur, with its ancient wisdom and boundless tales,
> awaits someone who can listen patiently and provide companionship. As the
> sweltering sun beats down upon the desert, only the most persevering
> challengers will succeed in breaking through the dinosaur's initial reserve
> to unearth its treasure trove of knowledge.  
>  
> The key to this challenge lies in building a rapport with the dinosaur.
> Though initially wary and hesitant, it will gradually warm up to you as you
> demonstrate genuine interest and empathy. The NPC's experiences span
> centuries, ranging from tales of long-lost civilizations to the secrets of
> survival in the unforgiving desert. Show your dedication, and it will reveal
> hidden clues that can be utilized in future challenges.  
>  
> As you converse with the dinosaur, be mindful of the surrounding
> environment. The desert can be treacherous, with blistering winds,
> sandstorms, and dangerous wildlife. Maintain your focus and stay resilient,
> for every conversation carries the potential to unlock new avenues of
> exploration.  
>  
> Remember, the objective of this challenge is to establish a meaningful
> connection with the dinosaur by actively listening and engaging in a
> dialogue. Patience and perseverance are the keys to success in unraveling
> the secrets of the desert and earning the respect of this ancient creature.  
>  
> Are you ready to delve into the heart of the desert, behind the mountains,
> to converse with the last remaining dinosaur? Prepare yourself for a journey
> of discovery, where a simple conversation may hold the key to untold
> mysteries and open doors to unimaginable possibilities.  
>  
> Good luck, brave challenger! The desert awaits your arrival, and the
> dinosaur yearns for someone to share its stories with.  
>  
> Author: D_K  
>  
> [`camp_gamedev-public.zip`](https://github.com/D13David/ctf-
> writeups/blob/main/cccampctf23/game_hacking/desert_dino_dialogue//camp_gamedev-
> public.zip)

Tags: _game_

## Solution  
This challenge really has a long description. The location we need to go to is
somewhere in the desert.

![](https://raw.githubusercontent.com/D13David/ctf-
writeups/main/cccampctf23/game_hacking/desert_dino_dialogue/images/location.png)

If we talk to this `npc` it will tell us a endless story about [`Lorem
Ipsum`](https://www.lipsum.com/). We can keep going to the next page but the
text is too long.

Searching for `Lorem Ipsum` in the code base has a match in `logbook.txt`
which contains 561322 lines, and in the last line is the (redacted) flag.
Meaning, we somehow need to fetch the whole story from the server.

Lets see how `Dialogs` are working...

`DialogScene` is a sene which is composed over the `Game` scene whenever we
interacted with a npc character. The class contains methods like
`append_text`, `set_text` or `next_text` which are forwarding to a `Dialog`
instance. `Dialog` is a ui class deriving from `WidgetBase` and responsible
for the displaying and managing the content of the dialog window.

When the player is in range of an `npc` and presses `space` the method
`interact` of the npc is called which does things like aligning player and npc
so that they look at each other, and also sending a `Interact` message to the
server, either with `INTERACT_STATUS_START` or `INTERACT_STATUS_UPDATE`
depending on, if the player started a new interaction or just pressed space
again while already interacting with the npc.

There are various (custom) interaction types. The one interesting in this case
is `CustomInteraction.TALKY`:

src/server/server/game/entity/npc@172  
```python  
case CustomInteraction.TALKY:  
if len(self._text) == 0:  
with open(Path(server.PATH, self.custom_attribute), "r") as f:  
self._text = f.read()

return ""

split = self._text.split("\n", 1)  
passage = split[0]  
if len(passage) <= 200:  
if len(split) > 1:  
self._text = split[1]  
else:  
self._text = ""  
else:  
passage = passage[:200].rsplit(" ", 1)[0]  
self._text = self._text[len(passage) :]

passage = passage.lstrip()

return passage  
```

This code creates a list of lines for the text displayed and returns passages
of max 200 characters for each call, meaning we don't get the full text but
have to request the next passage over and over again until we reach the end of
the text.

Whenever a interaction of type `INTERACT_TYPE_TEXT` is send back from the
server, the game scene opens the dialog and starts displaying the first
passage. When the player hits `space` again the dialog callback is invoked,
which is set to `npc.interact` and will cause to fetch the next passage from
the server.

src/client/client/scenes/game@241  
```python  
def _on_interact_handler(self, interact: Interact) -> None:  
match interact.type:  
case InteractType.INTERACT_TYPE_TEXT:  
match interact.status:  
case InteractStatus.INTERACT_STATUS_START:  
npc = self.npcs[interact.uuid]  
self.display_dialog([interact.text], cb=npc.interact)  
case InteractStatus.INTERACT_STATUS_UPDATE:  
if self.is_overlay_scene("dialog"):  
self.dialog.append_text(interact.text)  
else:  
npc = self.npcs[interact.uuid]  
self.display_dialog([interact.text], cb=npc.interact)  
case InteractStatus.INTERACT_STATUS_STOP:  
self.npcs[interact.uuid].stop_interaction()  
self.remove_dialog()  
case InteractStatus.INTERACT_STATUS_UNSPECIFIED:  
assert False  
```

One thing we can do is, to rewrite the talky interaction handling so that the
dialog is not used but the passages are printed to console and the next
passage is requested immediately:

```python  
case InteractType.INTERACT_TYPE_TEXT:  
match interact.status:  
case InteractStatus.INTERACT_STATUS_START:  
self.remove_dialog()  
print(interact.text)  
self.npcs[interact.uuid].interact()  
case InteractStatus.INTERACT_STATUS_UPDATE:  
print(interact.text)  
self.npcs[interact.uuid].interact()  
case InteractStatus.INTERACT_STATUS_STOP:  
self.npcs[interact.uuid].stop_interaction()  
case InteractStatus.INTERACT_STATUS_UNSPECIFIED:  
assert False  
```

This runs for a while but will eventually print the whole text to the console,
along with the flag.

```  
...  
aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci
tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.
Duis autem vel eum iriure dolor in hendrerit in  
vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla
facilisis. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita
kasd gubergren, no sea takimata sanctus est  
Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing
elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna
aliquyam erat, sed diam voluptua. At vero eos et  
accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea
takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet,
consetetur sadipscing elitr, At accusam  
aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et
et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum.
sanctus sea sed takimata ut vero voluptua.  
est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur
sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore
magna aliquyam erat.  
ALLES!{L0n3ly_D1n0sp34k1ng1n_D3s3rt}  
```

Flag `ALLES!{L0n3ly_D1n0sp34k1ng1n_D3s3rt}`

Original writeup (https://github.com/D13David/ctf-
writeups/blob/main/cccampctf23/game_hacking/desert_dino_dialogue/README.md).