Here you are, playing a CTF with you mates in Hamburg. You notice there’s a new task, “Nokia 1337”.
Enter the trilogy: pwn this phone. Please use only the qemu provided.
Remote instance requires proof of work: nc 188.40.18.78 1024Connect locally via telnet to localhost:10023 after qemu booted completely.
You download the image, fire it up in Qemu and…
![]() |
|
See the phone boot up on http://q3k.org/nokiaboot.webm
|
…Oh. Oh my.
Club Mate and Rum (it’s called a Tschunk!) in hand, you give it a shot…
The challenge
The bug
Set sail for fail.
The index parameter is given by the caller to identify the ID of the template we want to retrieve. intidptr can be provided by the user to get information on the internal DB ID of the template. textptr is the output buffer address given by the caller. lenptr can be passed to receive the amount of data written to the buffer.
As you might’ve noticed, there isn’t really a way for the caller to get the template length before calling the function – this looks bad. So, where is this function used? Well, when we wish to insert the template into our SMS. Here’s the relevant code:
Iceberg, right ahead!
This is the code called when the user selects a template to be inserted into an SMS message. text, at 0x1C600, is a global buffer of the currently edited text message, text_len is a global int of the current text message length. How large is text, you ask?
Your shipment of fail has arrived,
And since a template can also be 160 characters… Whoops! We have an overflow past the end of this buffer.
The exploit
![]() |
| Eww. |
The next structure that we can overflow is screen_sms_write, a structure defining the callbacks that are called by the UI layer when we leave, enter, or input data in the SMS write screen. This looks promising! The first callback normally points to sms_write_enter, and is called when we enter the SMS write screen. So, in theory, we could overflow that pointer, leave the SMS text editor, re-enter it and then the code execution would jump wherever we want. Nice, let’s try that.
![]() |
| Groovy, Baby! Yeah! |
Let’s say we make a 160-byte long template, with the last four bytes containing the address we want to write into the first callback at 0x1C6D4. Since the message buffer starts at 0x1C600, this means that our combined message+template text should have 216 bytes. Since the template is 160-bytes long, our message should be 56 bytes long. Here’s what I did to test whether this attack works:
- I created a new template, with 156 ‘B’ characters and 4 ‘Z’ characters. I saved it into memory.
- I created a new message, with 56 ‘A’ characters. I then inserted the previously crafted template at the end.
- I exited the message editor and re-entered it.
- I observed that the UI crashed.
Weaponization
![]() |
| ‘shiiii’ is the sound I make each time I look at this. |
- Create a new template, with 156 ‘A’ characters and 4 bytes of our shellcode address – 0x1C604. Remember, we can’t send zeroes, so I had to add 4 to the message buffer address.
- Create a new message with our shellcode, padded from the left with 4 ‘Z’ characters, and from the right with enough ‘Z’ characters to make the whole thing be 56 bytes long. Now our shellcode is at 0x1C604 in memory.
- Insert our template. Now we’ve overflowed 0x1C64, our shellcode address, into the sms_write_enter callback.
- Exit the message screen, and re-enter it. Now we’re executing our shellcode, which in turn dooes execve(“/bin/sh\0”, 0, 0).
- Get flag.
- ????
- PROFIT
But there are two parts left…. stay tuned.






