Skip to content

CarPrey jeopardy challenge and writeup from iCTF 2019

Notifications You must be signed in to change notification settings

saagarjha/ictf-carprey

Repository files navigation

ictf-carprey

CarPrey was a jeopardy challenge from iCTF 2019 that I designed and implemented. It's meant to be a mixed forensics/pwn challenge.

Solution

Connecting to CarPlay gets us a PoW challege immediately:

$ nc carpreylb-514290978.us-west-1.elb.amazonaws.com 2014
Prefix: 0177e60a2cea4d8eaf64474fa162fd12
Difficulty: 20

Using the pow.py script, we enter the PoW and the challenge will seemingly hang:

$ nc carpreylb-514290978.us-west-1.elb.amazonaws.com 2014
Prefix: 0177e60a2cea4d8eaf64474fa162fd12
Difficulty: 20
3769405

However, a bit of experimentation will reveal that it is actually waiting for user input, and that it is somewhat picky about what it will accept. The behavior of socat (which is what drove the network interaction in the backend) is a bit annoying in indicating when it has hung up, making this somewhat more difficult than it needed to be, but the hope was that you would eventually type something like "aa" or "00" and get back output, eventually realizing that the challenge accepts strings of the form [0-9A-Fa-f]{1,49}[0-9A-Fa-f]{1,49} (i.e. hex strings of even length between [2, 100)):

$ nc carpreylb-514290978.us-west-1.elb.amazonaws.com 2014
Prefix: 0177e60a2cea4d8eaf64474fa162fd12
Difficulty: 20
3769405
00
P1
? ?
011100000000000000000100000000000000000000000000011100011100111110111110000000000000000000000000100010000000000000001000000000000000011110000000001000100010001000100000000000000000000000000000100010011100110100010000111100101100100010110100001000100000001000100000000000000000000000000000111110100000101010010000100010110010100010101010001000100000001000111100000000000000000000000000100010011100101010010000111100100000011110101010001000100000001000100000000000000000000000000000100010000010100010001000100000100000000010100010001000100010001000100000000000000000000000000000100010111100100010000100100000100000011100100010011100011100001000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

You will recognize, hopefully by the magic, that this is actually a Netpbm plain PBM image, except that it's missing the dimensions of the image. There are 6,144 pixels, and trying reasonable factors for the dimensions of the number and checking the result shows that the dimensions are 96×64:

This, along with the image's font, should make it clear that 1. this is running on a TI-83+ series calculator, and 2. there is some sort of assembly programming involved. This series of calculators has a mode where it's possible to program in machine code directly on the calculator directly by typing in hex codes, so the initial constraints on input are quite suspicious: it seems awfully likely that we are sending bytes that are being entered in a program and executed on the calculator. To test this, we write a simple "Hello, world!":

.nolist
#include "spasm-ng/inc/ti83plus.inc"
.list
.org userMem
shellcode:
	b_call _HomeUp
	b_call _ClrLCDFull
	ld hl, string
	b_call _PutS
	ret
string:
	.db "Hello, world!",0
.end
.end

Assemble it and grab the hex, ef5845ef404521a29def0a45c948656c6c6f2c20776f726c642100, and then run the program and fix up the PBM:

So the challenge is just running our code directly, as we suspected. Now we just need to find the flag and print it. There are two decent ways to do this: one is to remember that the flag is a string and the TI-83+ series has a set of variables for these, so we should try printing them (with additional stuff to make the flag actually print out nicely with nothing on top of it):

.nolist
#include "spasm-ng/inc/ti83plus.inc"
.list
; No t2ByteTok, tAsmCmp necessary
.org userMem
shellcode:
	; Turn off annoyances that will cover output
	res donePrgm, (iy+doneFlags)
	set curLock, (iy+curFlags)
	; Clear the screen and move the cursor to the top right
	b_call _HomeUp
	b_call _ClrLCDFull
	ld hl, string
	b_call _Mov9ToOp1
	b_call _FindSym
	; Skip the length prefix
	inc de
	inc de
	ex de, hl
	b_call _PutS
	ret
string:
	.db StrngObj,tVarStrng,tStr1,0,0
.end
.end

Another option would be to search the small 16-bit memory space for the string "flg{", which is entirely possible considering the Z80's MHz speed CPU and the execution time (which is unknown but likely something reasonable like a second). Either approach works and dumps the flag, which, formatted, looks like this:

(FWIW, piping to fold -w 96 is your friend if you're too lazy to actually create PBM images; this lets you look at the results from your terminal.)

Implementation details

The challenge runs on the TilEm emulator, utilizing the save state and macro functionality of the emulator. In a nutshell, when the project is set up, it starts from the "ictf_base.sav" state, which is the program editor with AsmPrgm already typed in, and the flag is converted to a program (based on flag.s) that loads the flag in to Str1, which is then converted to a keyboard macro so that it can be typed into the calculator. The macro then has a "run" macro concatenated to it to send the keypresses to actually run the program, then another one to clear the screen and go back to the starting state so that it is ready for actual input from the user. The state is saved in ictf.sav and the calculator exits. The implementation for user input is similar: it is converted to a macro, has the "run" macro appended, and entered; the calculator is allowed to run for a second and then the LCD buffer is dumped in the "P1" format and the program is then killed. This functionality has been hard-coded into the calculator (in addition to some thread safety and heap overflow fixes that affected the operation of the program) via a patch applied to it during compilation.

To try the challenge yourself, run:

# ./install_dependencies.sh && ./clone.sh && ./compile.sh && ./flag.sh
# ./launch.sh

Now, you can connect to the challenge at localhost:2014 (the year CarPlay was released, in case you're curious). You can also run exploit.py to solve the challenge:

$ ./exploit.py localhost 2014

This repository contains the actual challenge files, as well as some "goodies" that were used in the development of the challenge. The ROM file for a TI-84+ SE, ictf.rom, has been intentionally left out for legal reasons; please find a way to acquire this by yourself.

About

CarPrey jeopardy challenge and writeup from iCTF 2019

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published