Python script in writeup link  
# BCACTF Trailblazer [27 Solves] - 450 Points

```  
To boldly go where no one has gone before...  
```  
## Initial Analysis  
We are given a `trailblazer` ELF64.  
Looking at the `main` function initially, we see it calling a `check_flag`
function with out input (which is the flag)

## check_flag function  
Unfortunately, IDA was unable to render the `check_flag` function using
pesudocode or graph view, and we will soon see why.  
The check_flag function passes our input to `strlen` to check and see if
`len(inputFlag) === 47`

```assembly  
0x0000000000401203 <+12>: mov QWORD PTR [rbp-0x28],rdi ;move input which is
stored in the rdi register as a parameter into rbp-0x28  
0x0000000000401207 <+16>: mov rax,QWORD PTR [rbp-0x28] ;move input into rax  
0x000000000040120b <+20>: mov rdi,rax ;move input into rdi and pass into
strlen  
0x000000000040120e <+23>: call 0x401080 <strlen@plt>  
0x0000000000401213 <+28>: mov DWORD PTR [rbp-0x14],eax  
0x0000000000401216 <+31>: cmp DWORD PTR [rbp-0x14],0x2f ; check that len =
0x2f = 47  
```

Afterwards, it passes the address of a function into `perms()`  
```assembly  
0x0000000000401223 <+44>: mov QWORD PTR [rbp-0x10],0x401262 ;address of a
function (0x401262) moved into rbp-0x10  
0x000000000040122b <+52>: mov rax,QWORD PTR [rbp-0x28] ;input moved into rax  
0x000000000040122f <+56>: mov QWORD PTR [rbp-0x8],rax ;input moved into
rbp-0x8  
0x0000000000401233 <+60>: mov rax,QWORD PTR [rbp-0x10] ;function address moved
into rax  
0x0000000000401237 <+64>: mov rdi,rax ;address of function passed to perms  
0x000000000040123a <+67>: call 0x401196 <perms>  
0x000000000040123f <+72>: test eax,eax  
```  
Inside `perms`, it calls `mprotect()` to give write access to the function
address.  
This suggests that it is **probably a decode the code with your input**
challenge since our input (the flag), is used to **change the code in this
function** later on in some way.

Moving on, then function then does a xor operation between the **first 8 bytes
of our input** and the **first 8 bytes of the function**  
\- This decodes the **first 8 bytes of the function** `+107 to +115`  
\- By entering `bcactf{A....}`, we can see a glimpse of the correct decoded
code as the first 7 bytes are bound to be correct, though the last byte is
probably wrong which causes the code to be malformed

```assembly  
0x0000000000401243 <+76>: mov edi,0x402008  
0x0000000000401248 <+81>: call 0x401070 <puts@plt>  
0x000000000040124d <+86>: mov eax,0x1  
0x0000000000401252 <+91>: jmp 0x4011f5 <perms+95>  
0x0000000000401254 <+93>: mov rax,QWORD PTR [rbp-16] ;Base of the function -
in "rax"  
0x0000000000401258 <+97>: mov rbx,QWORD PTR [rbp-8] ;Base of our input - in
"rbx"  
0x000000000040125c <+101>: mov rdx,QWORD PTR [rbx] ;Move 8 bytes of our input
into rdx  
0x000000000040125f <+104>: xor QWORD PTR [rax],rdx ;Xor 8 bytes of our input
with 8 bytes of the function

;First 8 bytes of the decoded function (107-115)  
;=====  
0x0000000000401262 <+107>: mov rdx,QWORD PTR [rbx+8] ;Move next 8 byte of
input into rdx  
0x0000000000401266 <+111>: xor QWORD PTR [rax+0x27],rdx  
;=====  
;Malformed byte, because bcactf{x, the x (8th byte) is a malformed byte  
;Correct: xor QWORD PTR [rax+8], rdx  
```

We can guess that this code probably continues on in a similar pattern, where
the next **8 bytes of our input** are **xored with the next 8 bytes of the
encoded function to create another 8 bytes of the encoded function**  
So the first decoded 8 bytes of the decoded function should be:

```assembly  
mov rdx,QWORD PTR [rbx+8]  
xor QWORD PTR [rax+8], rdx ;The correct decoded instruction  
```  
And the next 8 bytes will be:  
```assembly  
mov rdx,QWORD PTR [rbx+16]  
xor QWORD PTR [rax+16], rdx  
```

## Solution

Brute-forcing every single character of the flag will take too long. Instead
since we know that our input is xored with the encoded function bytes, we have
this relationship:  
`Encoded Function Bytes ^ Input = Expected Decoded Function Bytes`  
Thus, we can simply **xor our expected bytes with the encoded bytes** to get
the flag!

Testing this on the first 8 bytes in python, we get the first part of the
flag: `bcactf{n`. I then proceeded to obtain all the `Encoded Function Bytes`
as well as the `Expected Decoded Function Bytes` by **assembling the expected
instructions using `pwntools.asm()`** [[Python Script
Here](trailblazerDecode.py)]

_**Note 1:**_ We can deduce that the last instruction chunk should be only **7
bytes** (since the input length is `47 bytes`). And since it is the end of a
function, we can deduce it is a **_function epilogue_ ** (accompanied with a
**return value of 0 since that is what the main function is expecting**)

\- It needs to be `eax` instead if not the last chunk won't be 7 bytes

```assembly  
mov eax, 0  
leave  
ret  
```

**_Note 2:_ ** You can obtain the `Encoded Function Bytes` by using
`Telescope` on `rbp-16`. However, these bytes are in **little-endian**, so do
convert them to **big-endian** when xoring it with the `Expected Decoded
Function Bytes`

Hence the flag we get is:

```  
bcactf{now_thats_how_you_blaze_a_trail_8ge52y9}  
```

## Learning Points

1\. Dealing with code **encoded using the correct input**

Original writeup (https://github.com/IRS-
Cybersec/ctfdump/tree/master/BCACTF%202021/RE/Trailblazer).Copied from original writeup at [https://www.pmnh.site/post/ctf-
deadsec-2023-trailblazer/](https://www.pmnh.site/post/ctf-
deadsec-2023-trailblazer/)

## Summary

One of the things that I love about CTFs is when they provide challenges that
don't require knowledge of weird language quirks or obscure exploits or (ugh)
guesswork but instead just a clear head and some common sense. Kudos to the
designer of the [DeadSec 2023 CTF](https://www.deadsec.xyz/) Trailblazer
challenge, which offered exactly this type of problem.

## Recon

The Trailblazer challenge provided exactly one page to the site and no source
code was provided. Visiting the home page of the site provided the following
text content:

```  
[0-9 a-z A-Z / " \\+ , ( ) . # \\[ \\] =]  
```

Visiting any other page of the site would result in the following `404` page:

![404 page](https://www.pmnh.site/images/ctf-2023-deadsec-
trailblazer/404_page.png)

Interesting to note that the image appearing on the page is generated from the
endpoint `/images/now` and appears to contain a timestamp.

One other observation is that the server is running the (Python) [waitress
framework](https://github.com/Pylons/waitress), which we can see from the
server headers:

```  
Server: waitress  
```

Now that we have a sense for the server and related software, let's solve this
challenge!

## Analysis

The endpoint `now`, combined with the contents of the generated image, should
be familiar to anyone who is at all familiar with the Python language, as
being the default format of a `datetime` object, and the Python library
function
[`datetime.now`](https://docs.python.org/3/library/datetime.html#datetime.datetime.now)
can be used to return the current timestamp:

```  
Python 3.8.10 (default, Mar 13 2023, 10:26:41)  
[GCC 9.4.0] on linux  
Type "help", "copyright", "credits" or "license" for more information.  
>>> import datetime  
>>> str(datetime.datetime.now())  
'2023-05-21 12:26:57.831648'  
```

We note that this matches what we see in the generated image. This allows us
to conclude that the solution path here is a sort of RCE which will lead to us
changing the contents of the image. We can easily verify this by picking some
other class-level functions in the `datetime` class such as `utcnow` or
`today`, which will generate the same image.

## Leading to a Solution

So at this point we know:

* The image is being generated by Python code probably `eval`'ed from a string like this: `datetime.**last-path-segment**()`  
* Certain characters are not allowed in the path segment (we assume this from the list of characters shown on the home page)  
* Our goal is to read the content of `flag.txt` (this was later provided as a hint although I solved the challenge prior to this hint being available)

Let's see if we can chain a simple method call first, since the injection
point ends with parens we know that the last part of our injection has to be a
function that takes no parameters. So the following works:

```  
/images/now().toordinal  
```

This results in an image with the following content `738861`. So we've
confirmed we can chain function calls as we had hoped, and the contents of the
image will reflect the return value of the last function call (`toordinal` is
a function on a `datetime` object as documented
[here](https://docs.python.org/3/library/datetime.html#datetime.datetime.toordinal)).

If you don't want further spoilers, you can safely stop here and try to build
the exploit chain yourself :grin:

## Reading a File

Finally, I had to come up with a way to read the content of the flag file and
ensure the contents of the file fed into the method chain, since we can't
inject carriage returns and other control structures due to the character set
limitations. Also, we can't use a typical `__globals__` type injection because
the `_` character is prohibited.

The path I took was to inject a Python [lambda
function](https://www.w3schools.com/python/python_lambda.asp), which allows
for arbitrary / simple inline code to be used to process typically an iterator
such as an array or string. Typically these are used to perform some sort of
processing on the input i.e. a transformation, but in this case we're just
using it as a vehicle to inject arbitrary code.

Lambda functions can be used in many Python library functions, but
[`map`](https://docs.python.org/3/library/functions.html#map) seemed like a
logcal choice. Since `map` requires an iterable parameter, and we are starting
from a `datetime` object, I decided to figure out how to get a `string` from
the `datetime` and then pass the `string` to the `map` function. I built up
the payload like so:

```  
/images/now().strftime(%22aaa%22).title --> AAA  
```

Remember we still have to end the injection with a parameterless function
invocation, there are many on `string`. `strftime` on the `datetime` class was
useful because it allows us to provide any arbitrary `string` as output. We
pass this lambda result to `strftime` to get the string value added into the
method chain. We iterate on a dummy array `[1]` so that the lambda function is
executed exactly once:

```  
/images/now().strftime(str(map(lambda a: a, [1]))).title --> '<Map Object At
0X7Fd1789Fd9A0>'  
```

Oops! From this we can see our basic premise works, but we need to convert the
`map` object (with a single element) to a printable string so we can see the
result in the image output, we do this by wrapping it with the
`str(list(...))` built-in functions:

```  
/images/now().strftime(str(list(map(lambda a: a, [1])))).title --> '[1]`  
```

Now we simply put an `open('flag.txt').read(100)` in the lambda and we should
have our flag:

```  
/images/now().strftime(str(list(map(lambda a: open("flag.txt").read(100),
[1])))).title  
```

And we see the flag is (partially) revealed!

![Partial Flag](https://www.pmnh.site/images/ctf-2023-deadsec-
trailblazer/flag_in_image.png)

Further work was required to see the whole flag, this was made a little more
painful because the font used in the image did not clearly indicate uppercase
and lowercase letters. We'll leave this as an exercise to the reader, try
reproducing this in your local Python CLI and see how you might iterate
through the characters :smile:

Overall a super fun challenge that required no brute force or guesswork but
just putting the pieces together. Thanks DeadSec!  

Original writeup (https://www.pmnh.site/post/ctf-deadsec-2023-trailblazer/).